IT

루비-배열이 아닌 경우 변수를 배열로 우아하게 변환

lottoking 2020. 7. 30. 09:37
반응형

루비-배열이 아닌 경우 변수를 배열로 우아하게 변환


배열, 단일 요소 또는 nil이 주어지면 배열을 얻습니다. 후자는 두 요소가 단일 요소 배열이고 빈 배열입니다.

나는 루비가 이런 식으로 수리 잘못 생각했다.

[1,2,3].to_a  #= [1,2,3]     # Already an array, so no change
1.to_a        #= [1]         # Creates an array and adds element
nil.to_a      #= []          # Creates empty array

실제로 얻는 것은 다음과 같습니다.

[1,2,3].to_a  #= [1,2,3]         # Hooray
1.to_a        #= NoMethodError   # Do not want
nil.to_a      #= []              # Hooray

방법을 사용하는 경우 사용하려는 모든 클래스의 사용 방법을 수정하여 메타 프로그램을 사용할 수 있습니다.

따라서 방법은 다음과 가변적입니다.

result = nums.class == "Array".constantize ? nums : (nums.class == "NilClass".constantize ? [] : ([]<<nums))

문제는 약간의 혼란스러워한다는 것입니다. 제출하는 우아한 방법이 있습니까? (이 문제를 루비 같은 방법이라면 놀랍습니다)


어떤 응용 프로그램이 있습니까? 왜 배열로 변환?

say라고 부르는 Rails의 ActiveRecord에서 user.posts게시물의 배열, 단일 게시물 또는 nil을 반환합니다. 이 결과에서 작동하는 메소드를 사용할 때 메소드가 0, 1 또는 많은 요소를 발생하는 배열을 수행합니다. 방법 예 :

current_user.posts.inject(true) {|result, element| result and (element.some_boolean_condition)}

[*foo]또는 Array(foo)대부분의 경우 작동하지만 해시와 같은 경우에는 엉망이됩니다.

Array([1, 2, 3])    # => [1, 2, 3]
Array(1)            # => [1]
Array(nil)          # => []
Array({a: 1, b: 2}) # => [[:a, 1], [:b, 2]]

[*[1, 2, 3]]    # => [1, 2, 3]
[*1]            # => [1]
[*nil]          # => []
[*{a: 1, b: 2}] # => [[:a, 1], [:b, 2]]

해시 가능한 유일한 방법은 메소드를 정의하는 것입니다.

class Object; def ensure_array; [self] end end
class Array; def ensure_array; to_a end end
class NilClass; def ensure_array; to_a end end

[1, 2, 3].ensure_array    # => [1, 2, 3]
1.ensure_array            # => [1]
nil.ensure_array          # => []
{a: 1, b: 2}.ensure_array # => [{a: 1, b: 2}]

ActiveSupport 사용 (레일) : Array.wrap

Array.wrap([1, 2, 3])     # => [1, 2, 3]
Array.wrap(1)             # => [1]
Array.wrap(nil)           # => []
Array.wrap({a: 1, b: 2})  # => [{:a=>1, :b=>2}]

Rails를 사용하지 않는 경우 rails source 와 사용할 수있는 고유 한 방법을 정의 할 수 있습니다 .

class Array
  def self.wrap(object)
    if object.nil?
      []
    elsif object.respond_to?(:to_ary)
      object.to_ary || [object]
    else
      [object]
    end
  end
end

가장 간단한 해결책은 사용하는 것 [foo].flatten(1)입니다. 다른 제안 된 솔루션과 달리 (중첩 된) 배열, 해시 및 nil다음에서 잘 작동합니다 .

def wrap(foo)
  [foo].flatten(1)
end

wrap([1,2,3])         #= [1,2,3]
wrap([[1,2],[3,4]])   #= [[1,2],[3,4]]
wrap(1)               #= [1]
wrap(nil)             #= [nil]
wrap({key: 'value'})  #= [{key: 'value'}]

Array(whatever) 트릭을해야합니다

Array([1,2,3]) # [1,2,3]
Array(nil) # []
Array(1337)   # [1337]

활성 지원 (레일)

ActiveSupport에는 이에 대한 꽤 좋은 방법이 있습니다. Rails가 포함되어 있으므로이를 수행하는 가장 좋은 방법은 다음과 같습니다.

Array.wrap([1, 2, 3]) #=> [1, 2, 3]
Array.wrap(nil) #=> nil

Splat (Ruby 1.9 이상)

표시 연산자 ( *)는 다음을 수행 할 수있는 경우 배열의 배열을 해제합니다.

*[1,2,3] #=> 1, 2, 3 (notice how this DOES not have braces)

물론, 배열이 없으면 이상한 일을하므로 "splat"객체를 배열에 넣어야합니다. 다소 이상하지만 다음을 의미합니다.

[*[1,2,3]] #=> [1, 2, 3]
[*5] #=> [5]
[*nil] #=> []
[*{meh: "meh"}] #=> [[:meh, "meh"], [:meh2, "lol"]]

ActiveSupport가없는 경우 방법을 정의 할 수 있습니다.

class Array
    def self.wrap(object)
        [*object]
    end
end

Array.wrap([1, 2, 3]) #=> [1, 2, 3]
Array.wrap(nil) #=> nil

비록 당신이 큰 배열을 가지고 있고 배열이 아닌 것을 덜 계획한다면, 그것을 변경하고 싶을 수도 있습니다. 위의 방법은 큰 배열에서 느리고 스택이 오버플로 될 수도 있습니다 (omg so meta). 어쨌든 대신 이것을 할 수 있습니다.

class Array
    def self.wrap(object)
        object.is_a? Array ? object : [*object]
    end
end

Array.wrap([1, 2, 3]) #=> [1, 2, 3]
Array.wrap(nil) #=> [nil]

또한 테너 레이 연산자가 있거나없는 몇 가지 벤치 마크 가 있습니다.


어때

[].push(anything).flatten

명백한 것을 말할 위험이 있고 이것이 지구와 주변 지역에서 본 것 중 가장 맛있는 구문 설탕이 아니라는 것을 알면이 코드는 당신이 설명하는 것과 정확히 일치하는 것처럼 보입니다.

foo = foo.is_a?(Array) ? foo : foo.nil? ? [] : [foo]

Object의 배열 메소드를 덮어 쓸 수 있습니다.

class Object
    def to_a
        [self]
    end
end

모든 것이 Object를 상속하므로 이제 to_a는 태양 아래의 모든 것에 대해 정의됩니다.


모든 답변을 검토했으며 대부분 루비 2+에서는 작동하지 않습니다.

그러나 elado에는 가장 우아한 솔루션이 있습니다.

ActiveSupport (레일) 사용 : Array.wrap

Array.wrap ([1, 2, 3]) # => [1, 2, 3]

Array.wrap (1) # => [1]

Array.wrap (nil) # => []

Array.wrap ({a : 1, b : 2}) # => [{: a => 1, : b => 2}]

슬프게도 루비 2+에서는 오류가 발생하므로 작동하지 않습니다.

undefined method `wrap' for Array:Class

따라서 수정하려면 필요합니다.

'active_support / deprecation'필요

'active_support / core_ext / array / wrap'필요


#to_a두 가지 주요 문제 클래스 ( NilHash)에 대한 메서드가 이미 존재 하므로 다음 을 확장하여 나머지 메서드를 정의하기 만하면됩니다 Object.

class Object
    def to_a
        [self]
    end
end

그런 다음 모든 객체에서 해당 메서드를 쉽게 호출 할 수 있습니다.

"Hello world".to_a
# => ["Hello world"]
123.to_a
# => [123]
{a:1, b:2}.to_a
# => [[:a, 1], [:b, 2]] 
nil.to_a
# => []

참고 URL : https://stackoverflow.com/questions/18358717/ruby-elegantly-convert-variable-to-an-array-if-not-an-array-already

반응형