programing

루비 - 아직 배열이 아닌 경우 변수를 배열로 우아하게 변환합니다).

skycolor 2023. 6. 1. 22:37
반응형

루비 - 아직 배열이 아닌 경우 변수를 배열로 우아하게 변환합니다).

배열이 주어지면 단일 요소 또는 0이 배열을 얻습니다. 후자의 두 요소는 각각 단일 요소 배열과 빈 배열입니다.

나는 루비가 이런 식으로 작동할 것이라고 잘못 생각했습니다.

[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

그래서 이것을 해결하기 위해, 저는 다른 방법을 사용해야 하거나, 제가 사용하고자 하는 모든 클래스의 방법을 to_a로 수정하여 프로그램을 만날 수 있습니다. 이것은 저에게 선택사항이 아닙니다.

방법은 다음과 같습니다.

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

문제는 그것이 약간 엉망이라는 것입니다.이것을 하는 우아한 방법이 있습니까?(만약 이것이 이 문제를 해결하는 루비 같은 방법이라면 저는 놀랄 것입니다.)


이것은 어떤 응용 프로그램이 있습니까?어레이로 변환할 필요가 있습니까?

레일즈의 액티브 레코드에서 전화를 걸어 이렇게 말합니다.user.posts게시물 배열, 단일 게시물 또는 0을 반환합니다.이 결과에 영향을 미치는 메소드를 작성할 때 메소드가 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}]

액티브 지원(레일) 포함: 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}]

레일을 사용하지 않는 경우 레일 소스와 유사한 방법을 정의할 수 있습니다.

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는 이를 위한 매우 좋은 방법을 제공합니다.레일즈가 탑재되어 있으므로 도전적으로 가장 좋은 방법은 다음과 같습니다.

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

스플랫(루비 1.9+)

스플랫 연산자(*) 배열을 해제합니다(가능한 경우).

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

물론, 배열이 없으면 이상한 일이 발생하고, "스플릿"하는 개체는 배열에 넣어야 합니다.좀 이상하지만, 의미는 다음과 같습니다.

[*[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]

개체의 배열 방법을 덮어쓸 수 있습니다.

class Object
    def to_a
        [self]
    end
end

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

나는 모든 답을 검토했고 대부분 루비 2+에서 일하지 않습니다.

하지만 엘라도는 가장 우아한 해결책을 가지고 있습니다.

액티브 지원(레일) 포함: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/decretion'이(가) 필요합니다.

'active_support/core_ext/array/message'가 필요합니다.

메소드 이후로#to_a 가지 가 있는클래스에 합니다.Nil그리고.Hash), 을 통해 하면 됩니다.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

반응형