Ruby에서는 다음 형식 중 하나의 배열이 제공됩니다.
[apple, 1, banana, 2]
[[apple, 1], [banana, 2]]
…이를 해시로 변환하는 가장 좋은 방법은 무엇입니까?
{apple => 1, banana => 2}
답변
참고 : 간결하고 효율적인 솔루션은 아래 Marc-André Lafortune의 답변을 참조하십시오.
이 답변은 원래 글을 쓰는 시점에서 가장 많이 찬성 된 flatten을 사용하는 접근 방식의 대안으로 제공되었습니다. 이 예제를 모범 사례 나 효율적인 접근 방식으로 제시 할 의도가 아님을 분명히해야했습니다. 원래 대답은 다음과 같습니다.
경고! 평면화 를 사용 하는 솔루션 은 배열 키 또는 값을 보존하지 않습니다!
@John Topley의 인기있는 답변을 바탕으로 시도해 보겠습니다.
a3 = [ ['apple', 1], ['banana', 2], [['orange','seedless'], 3] ]
h3 = Hash[*a3.flatten]
이로 인해 오류가 발생합니다.
ArgumentError: odd number of arguments for Hash
from (irb):10:in `[]'
from (irb):10
생성자는 짝수 길이의 배열 (예 : [ ‘k1’, ‘v1,’k2 ‘,’v2 ‘])을 예상했습니다. 더 나쁜 것은 짝수 길이로 평평한 다른 배열이 잘못된 값을 가진 해시를 조용히 제공한다는 것입니다.
배열 키 또는 값을 사용하려면 map 을 사용할 수 있습니다 .
h3 = Hash[a3.map {|key, value| [key, value]}]
puts "h3: #{h3.inspect}"
이렇게하면 배열 키가 유지됩니다.
h3: {["orange", "seedless"]=>3, "apple"=>1, "banana"=>2}
답변
간단히 사용 Hash[*array_variable.flatten]
예를 들면 :
a1 = ['apple', 1, 'banana', 2]
h1 = Hash[*a1.flatten(1)]
puts "h1: #{h1.inspect}"
a2 = [['apple', 1], ['banana', 2]]
h2 = Hash[*a2.flatten(1)]
puts "h2: #{h2.inspect}"
사용 Array#flatten(1)
하면 재귀가 제한되므로 Array
키와 값이 예상대로 작동합니다.
답변
가장 좋은 방법은 Array#to_h
.
[ [:apple,1],[:banana,2] ].to_h #=> {apple: 1, banana: 2}
참고 to_h
또한 블록을 허용합니다
[:apple, :banana].to_h { |fruit| [fruit, "I like #{fruit}s"] }
# => {apple: "I like apples", banana: "I like bananas"}
참고 : to_h
Ruby 2.6.0 이상에서는 블록을 허용합니다. 초기 루비의 경우 내backports
보석을 하고require 'backports/2.6.0/enumerable/to_h'
to_h
블록없이 루비 2.1.0에서 도입되었습니다.
Ruby 2.1 이전에는 덜 읽기 쉬운 Hash[]
다음을 사용할 수있었습니다 .
array = [ [:apple,1],[:banana,2] ]
Hash[ array ] #= > {:apple => 1, :banana => 2}
마지막으로를 사용하는 솔루션에주의하십시오 flatten
. 이것은 배열 자체 인 값에 문제를 일으킬 수 있습니다.
답변
최신 정보
Ruby 2.1.0이 오늘 출시되었습니다 . 그리고 나는 Array#to_h
( 릴리스 노트 및 ruby-doc ) 와 함께 제공되며 , 이는 an Array
을 a 로 변환하는 문제를 해결합니다 .Hash
.
Ruby 문서 예 :
[[:foo, :bar], [1, 2]].to_h # => {:foo => :bar, 1 => 2}
답변
편집 : 내가 글을 쓰는 동안 게시 된 응답을 보았습니다. Hash [a.flatten]가 갈 길인 것 같습니다. 응답을 통해 생각할 때 문서에서 그 부분을 놓쳤을 것입니다. 필요한 경우 내가 작성한 솔루션을 대안으로 사용할 수 있다고 생각했습니다.
두 번째 형식은 더 간단합니다.
a = [[:apple, 1], [:banana, 2]]
h = a.inject({}) { |r, i| r[i.first] = i.last; r }
a = 배열, h = 해시, r = 반환 값 해시 (우리가 축적 한 것), i = 배열의 항목
첫 번째 형식을 수행하는 가장 좋은 방법은 다음과 같습니다.
a = [:apple, 1, :banana, 2]
h = {}
a.each_slice(2) { |i| h[i.first] = i.last }
답변
다음을 사용하여 2D 배열을 해시로 간단히 변환 할 수도 있습니다.
1.9.3p362 :005 > a= [[1,2],[3,4]]
=> [[1, 2], [3, 4]]
1.9.3p362 :006 > h = Hash[a]
=> {1=>2, 3=>4}
답변
요약 및 요약 :
이 답변은 다른 답변의 정보에 대한 포괄적 인 요약이되기를 바랍니다.
질문의 데이터와 몇 가지 추가 사항을 고려할 때 매우 짧은 버전 :
flat_array = [ apple, 1, banana, 2 ] # count=4
nested_array = [ [apple, 1], [banana, 2] ] # count=2 of count=2 k,v arrays
incomplete_f = [ apple, 1, banana ] # count=3 - missing last value
incomplete_n = [ [apple, 1], [banana ] ] # count=2 of either k or k,v arrays
# there's one option for flat_array:
h1 = Hash[*flat_array] # => {apple=>1, banana=>2}
# two options for nested_array:
h2a = nested_array.to_h # since ruby 2.1.0 => {apple=>1, banana=>2}
h2b = Hash[nested_array] # => {apple=>1, banana=>2}
# ok if *only* the last value is missing:
h3 = Hash[incomplete_f.each_slice(2).to_a] # => {apple=>1, banana=>nil}
# always ok for k without v in nested array:
h4 = Hash[incomplete_n] # or .to_h => {apple=>1, banana=>nil}
# as one might expect:
h1 == h2a # => true
h1 == h2b # => true
h1 == h3 # => false
h3 == h4 # => true
토론 및 세부 사항은 다음과 같습니다.
설정 : 변수
우리가 사용할 데이터를 보여주기 위해 데이터에 대한 다양한 가능성을 나타내는 몇 가지 변수를 만들겠습니다. 다음 범주에 해당합니다.
질문에 직접 포함 된 내용을 기반으로 다음 a1
과 a2
같습니다.
(참고 : 나는 그것을 가정 apple
및 banana
변수를 나타내는 것을 의미하고 다른 사람이했던 것처럼, 나는 그 입력과 결과가 일치 할 수 있도록 여기에서 문자열을 사용됩니다.).
a1 = [ 'apple', 1 , 'banana', 2 ] # flat input
a2 = [ ['apple', 1], ['banana', 2] ] # key/value paired input
다중 값 키 및 / 또는 값 a3
:
다른 답변에서 또 다른 가능성이 제시되었습니다 (여기에서 확장합니다). 키 및 / 또는 값은 자체적으로 배열 일 수 있습니다.
a3 = [ [ 'apple', 1 ],
[ 'banana', 2 ],
[ ['orange','seedless'], 3 ],
[ 'pear', [4, 5] ],
]
불균형 어레이, a4
:
좋은 측정을 위해 불완전한 입력이있을 수있는 경우 하나를 추가 할 것이라고 생각했습니다.
a4 = [ [ 'apple', 1],
[ 'banana', 2],
[ ['orange','seedless'], 3],
[ 'durian' ], # a spiky fruit pricks us: no value!
]
이제 작동합니다.
처음에는 평평한 배열로 시작하여 a1
.
일부는 #to_h
(Ruby 2.1.0에 나타 났으며 이전 버전 으로 백 포트 할 수있는) 사용을 제안했습니다 . 초기 플랫 배열의 경우 작동하지 않습니다.
a1.to_h # => TypeError: wrong element type String at 0 (expected array)
splat 연산자Hash::[]
와 함께 사용하면 다음이 수행됩니다.
Hash[*a1] # => {"apple"=>1, "banana"=>2}
이것이 다음으로 표현되는 간단한 사례에 대한 해결책입니다. a1
.
키 / 값 쌍 배열의 배열을 사용하면 a2
다음을 수행합니다.
배열로 [key,value]
형 배열, 이동하는 방법은 두 가지가 있습니다.
첫째, Hash::[]
여전히 작동합니다 (에서와 같이 *a1
).
Hash[a2] # => {"apple"=>1, "banana"=>2}
그리고 #to_h
지금도 작동합니다.
a2.to_h # => {"apple"=>1, "banana"=>2}
따라서 간단한 중첩 배열 사례에 대한 두 가지 쉬운 대답입니다.
이는 다음과 같이 하위 배열을 키 또는 값으로 사용하더라도 마찬가지입니다 a3
.
Hash[a3] # => {"apple"=>1, "banana"=>2, ["orange", "seedless"]=>3, "pear"=>[4, 5]}
a3.to_h # => {"apple"=>1, "banana"=>2, ["orange", "seedless"]=>3, "pear"=>[4, 5]}
그러나 두리안에는 스파이크가 있습니다 (변칙적 인 구조로 인해 문제가 발생 함).
균형이 맞지 않는 입력 데이터가 있으면 다음과 #to_h
같은 문제가 발생합니다 .
a4.to_h # => ArgumentError: wrong array length at 3 (expected 2, was 1)
그러나 Hash::[]
여전히 작동 nil
합니다. durian
(및 a4의 다른 모든 배열 요소 (단지 1- 값 배열))로 설정하면됩니다.
Hash[a4] # => {"apple"=>1, "banana"=>2, ["orange", "seedless"]=>3, "durian"=>nil}
평면화-새 변수 사용 a5
및a6
인수의 flatten
유무에 관계없이 몇 가지 다른 답변이 언급 1
되었으므로 새로운 변수를 만들어 보겠습니다.
a5 = a4.flatten
# => ["apple", 1, "banana", 2, "orange", "seedless" , 3, "durian"]
a6 = a4.flatten(1)
# => ["apple", 1, "banana", 2, ["orange", "seedless"], 3, "durian"]
나는 a4
우리가 가진 균형 문제 때문에 기본 데이터 로 사용하기 로 결정했습니다 a4.to_h
. 나는 전화를flatten
는 누군가가 그것을 해결하기 위해 사용할 수있는 한 가지 접근 방식 일 수 있다고 생각합니다. 다음과 같이 보일 수 있습니다.
flatten
인수 없음 ( a5
) :
Hash[*a5] # => {"apple"=>1, "banana"=>2, "orange"=>"seedless", 3=>"durian"}
# (This is the same as calling `Hash[*a4.flatten]`.)
순진한 눈에 작업이 나타납니다이 -하지만 이렇게도 만드는 씨없는 오렌지 잘못된 도보로 우리를 얻었다 키 와 값을 .3
durian
그리고 이것은에서와 a1
마찬가지로 작동하지 않습니다.
a5.to_h # => TypeError: wrong element type String at 0 (expected array)
그래서 a4.flatten
우리에게는 유용하지 않습니다.Hash[a4]
flatten(1)
경우 ( a6
)
그러나 부분적으로 만 평평하게하는 것은 어떻습니까? 부분적으로 평면화 된 배열 ( ) 에서 Hash::[]
using 을 호출 하는 것은 다음을 호출하는 것과 동일 하지 않다는 점에 주목할 가치가 있습니다 .splat
a6
Hash[a4]
Hash[*a6] # => ArgumentError: odd number of arguments for Hash
미리 병합 된 배열, 여전히 중첩 됨 (다른 방법으로 a6
) :
그러나 이것이 우리가 처음에 배열을 얻은 방법이라면 어떨까요? (즉,에 비해 a1
입력 데이터였습니다. 이번에는 일부 데이터가 배열이나 다른 객체가 될 수 있습니다.) Hash[*a6]
작동하지 않는 것을 보았습니다. 하지만 여전히 작동하지 않는 동작을 얻으려면 어떻게해야합니까? 마지막 요소 (중요! 아래 참조)는nil
값 했습니까?
이러한 상황에서도 Enumerable#each_slice
키 / 값 쌍 을 외부 배열의 요소로 되 돌리는 데 사용하는 방법이 여전히 있습니다 .
a7 = a6.each_slice(2).to_a
# => [["apple", 1], ["banana", 2], [["orange", "seedless"], 3], ["durian"]]
이것은 ” 동일 ” a4
하지 않지만 동일한 값을 갖는 새로운 배열을 얻게 됩니다 .
a4.equal?(a7) # => false
a4 == a7 # => true
따라서 다시 사용할 수 있습니다 Hash::[]
.
Hash[a7] # => {"apple"=>1, "banana"=>2, ["orange", "seedless"]=>3, "durian"=>nil}
# or Hash[a6.each_slice(2).to_a]
하지만 문제가 있습니다!
each_slice(2)
솔루션은 마지막 키가 값이 누락 된 경우에만 모든 것을 정상 상태로 되 돌린다는 점에 유의하는 것이 중요 합니다. 나중에 추가 키 / 값 쌍을 추가 한 경우 :
a4_plus = a4.dup # just to have a new-but-related variable name
a4_plus.push(['lychee', 4])
# => [["apple", 1],
# ["banana", 2],
# [["orange", "seedless"], 3], # multi-value key
# ["durian"], # missing value
# ["lychee", 4]] # new well-formed item
a6_plus = a4_plus.flatten(1)
# => ["apple", 1, "banana", 2, ["orange", "seedless"], 3, "durian", "lychee", 4]
a7_plus = a6_plus.each_slice(2).to_a
# => [["apple", 1],
# ["banana", 2],
# [["orange", "seedless"], 3], # so far so good
# ["durian", "lychee"], # oops! key became value!
# [4]] # and we still have a key without a value
a4_plus == a7_plus # => false, unlike a4 == a7
그리고 여기서 얻을 수있는 두 개의 해시는 중요한면에서 다릅니다.
ap Hash[a4_plus] # prints:
{
"apple" => 1,
"banana" => 2,
[ "orange", "seedless" ] => 3,
"durian" => nil, # correct
"lychee" => 4 # correct
}
ap Hash[a7_plus] # prints:
{
"apple" => 1,
"banana" => 2,
[ "orange", "seedless" ] => 3,
"durian" => "lychee", # incorrect
4 => nil # incorrect
}
(참고 : 여기서 구조를 더 쉽게 표시하기 위해 awesome_print
‘s ap
를 사용하고 있습니다. 이에 대한 개념적 요구 사항은 없습니다.)
따라서 each_slice
불평형 플랫 입력에 대한 솔루션은 불평형 비트가 맨 끝에있는 경우에만 작동합니다.
요약 :
- 가능하면 이러한 것에 대한 입력을
[key, value]
쌍으로 설정하십시오 (외부 배열의 각 항목에 대한 하위 배열). - 실제로 그렇게 할 수 있으면 둘 중 하나
#to_h
또는Hash::[]
둘 다 작동합니다. - 할 수없는 경우 입력이 균형을 이루는
Hash::[]
한 splat (*
) 과 함께 사용할 수 있습니다. - 으로 불균형 및 평면 경우 입력으로 배열, 전혀 유일한 방법이 의지의 작품은 합리적이고 마지막
value
항목이 실종있는 유일한 사람입니다.
참고 사항 : 추가 할 가치가 있다고 생각하기 때문에이 답변을 게시하고 있습니다. 기존 답변 중 일부에는 잘못된 정보가 있으며 여기에서 수행하려는 것만 큼 완전한 답변을 제공 한 사람은 없습니다. 도움이 되었기를 바랍니다. 그럼에도 불구하고 나는이 답변의 일부에 영감을 주었던 제 앞에 오신 분들께 감사드립니다.
