답변:
참고 : 간결하고 효율적인 솔루션은 아래 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}
h3 = Hash[*a3.flatten(1)]
대신 h3 = Hash[*a3.flatten]
오류가 발생합니다.
to_h
가 더 낫다고 생각 합니다.
간단히 사용 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
키와 값이 예상대로 작동합니다.
Hash[*ary.flatten(1)]
, 배열 키와 값을 보존 할을 사용할 수도 있습니다 . flatten
그것들을 파괴하는 것은 재귀 적 이며 피할 수있을만큼 쉽습니다.
가장 좋은 방법은 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
. 이것은 배열 자체 인 값에 문제를 일으킬 수 있습니다.
to_h
더 이상 답변보다는 방법은이 변환의 의도를 표현하기 때문에 후 배열에서 작동합니다.
Array#to_h
도는 Enumerable#to_h
코어 루비 1.9이다.
[[apple, 1], [banana, 2], [apple, 3], [banana, 4]]
이 있고 출력을 원하면 {"apple" =>[1,3], "banana"=>[2,4]}
어떻게합니까?
최신 정보
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 }
a.inject({})
보다 유연한 값 할당을 허용 하는 한 줄의 경우 +1 .
h = {}
로 끝나는 분사의 사용을 통해 두 번째 예제에서a.each_slice(2).inject({}) { |h,i| h[i.first] = i.last; h }
a.each_slice(2).to_h
이 답변은 다른 답변의 정보에 대한 포괄적 인 요약이되기를 바랍니다.
질문의 데이터와 몇 가지 추가 사항을 고려할 때 매우 짧은 버전 :
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
항목이 실종있는 유일한 사람입니다.참고 사항 : 추가 할 가치가 있다고 생각하기 때문에이 답변을 게시하고 있습니다. 기존 답변 중 일부에는 잘못된 정보가 있으며 여기에서 수행하려는 것만 큼 완전한 답변을 제공 한 사람은 없습니다. 도움이 되었기를 바랍니다. 그럼에도 불구하고 나는이 답변의 일부에 영감을 주었던 제 앞에 오신 분들께 감사드립니다.
답변에 추가하지만 익명 배열을 사용하고 주석을 추가합니다.
Hash[*("a,b,c,d".split(',').zip([1,2,3,4]).flatten)]
내부에서 시작하여 그 대답을 분리하십시오.
"a,b,c,d"
실제로 문자열입니다.split
쉼표로 배열에.zip
다음 배열과 함께.[1,2,3,4]
실제 배열입니다.중간 결과는 다음과 같습니다.
[[a,1],[b,2],[c,3],[d,4]]
flatten은 다음과 같이 변환합니다.
["a",1,"b",2,"c",3,"d",4]
그리고:
*["a",1,"b",2,"c",3,"d",4]
그것을 풀어
"a",1,"b",2,"c",3,"d",4
Hash[]
메서드에 대한 인수로 사용할 수 있습니다 .
Hash[*("a,b,c,d".split(',').zip([1,2,3,4]).flatten)]
결과 :
{"a"=>1, "b"=>2, "c"=>3, "d"=>4}
*
) 없이도 작동 하고 flatten : Hash[("a,b,c,d".split(',').zip([1,2,3,4]))]
=> {"a"=>1, "b"=>2, "c"=>3, "d"=>4}
. 내가 추가 한 답변에 더 자세히 설명되어 있습니다.
다음과 같은 배열이 있다면-
data = [["foo",1,2,3,4],["bar",1,2],["foobar",1,"*",3,5,:foo]]
각 배열의 첫 번째 요소가 해시의 키가되고 나머지 요소는 값 배열이되기를 원합니다. 그러면 다음과 같이 할 수 있습니다.
data_hash = Hash[data.map { |key| [key.shift, key] }]
#=>{"foo"=>[1, 2, 3, 4], "bar"=>[1, 2], "foobar"=>[1, "*", 3, 5, :foo]}
이것이 최선의 방법인지 확실하지 않지만 작동합니다.
a = ["apple", 1, "banana", 2]
m1 = {}
for x in (a.length / 2).times
m1[a[x*2]] = a[x*2 + 1]
end
b = [["apple", 1], ["banana", 2]]
m2 = {}
for x,y in b
m2[x] = y
end