루비에서 배열을 해시로 변환하는 가장 좋은 방법은 무엇입니까?
루비에서, 다음 형태 중 하나의 배열이 주어지면...
[apple, 1, banana, 2]
[[apple, 1], [banana, 2]]
...이것을 ...의 형태로 해시로 변환하는 가장 좋은 방법은 무엇입니까?
{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
키와 값이 예상대로 작동합니다.
참고: 간결하고 효율적인 솔루션은 아래 Marc-André Laforte의 답변을 참조하십시오.
이 답변은 원래 글을 쓸 당시 가장 많이 지지를 받았던 플랫을 사용한 접근 방식의 대안으로 제시되었습니다.이 사례를 모범 사례나 효율적인 접근 방식으로 제시할 의도가 없었다는 점을 분명히 했어야 합니다.원답은 다음과 같습니다.
경고!플랫을 사용하는 솔루션은 어레이 키 또는 값을 보존하지 않습니다!
@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')을 예상했습니다.더 나쁜 것은 짝수 길이로 평평해진 다른 배열이 잘못된 값을 가진 해시를 조용히 제공한다는 것입니다.
배열 키 또는 값을 사용하려면 맵:
h3 = Hash[a3.map {|key, value| [key, value]}]
puts "h3: #{h3.inspect}"
이렇게 하면 어레이 키가 유지됩니다.
h3: {["orange", "seedless"]=>3, "apple"=>1, "banana"=>2}
가장 좋은 방법은 다음을 사용하는 것입니다.
[ [: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
2할 수 의 경우 my Ruby 2.6.0+를 할 수 . 초기 루비의 경우 my를 사용할 수 있습니다.backports
보석과
to_h
Ruby 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
(릴리스 노트 및 루비 문서), 변환 문제를 해결합니다.Array
Hash
.
Ruby 문서 예제:
[[:foo, :bar], [1, 2]].to_h # => {:foo => :bar, 1 => 2}
편집: 제가 글을 쓰는 동안 올린 답변을 보니 해시[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}
요약 및 TL;DR:
이 답변은 다른 답변의 정보를 종합적으로 정리하는 것이 되기를 바랍니다.
질문의 데이터와 몇 가지 추가 사항을 고려할 때 매우 짧은 버전:
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
:
일부에서는 (Ruby 2.1.0에 표시되었으며 이전 버전으로 역포팅할 수 있음)을 사용할 것을 제안했습니다.초기 플랫 배열의 경우에는 다음과 같이 작동하지 않습니다.
a1.to_h # => TypeError: wrong element type String at 0 (expected array)
스플랫 연산자와 함께 사용하면 다음 작업이 수행됩니다.
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-배 열 한 른 다 배 열 요 소 불 과 에 및 값 는 에 : 요 ) 소 배 열 ▁a ▁( 른 ) ▁element 다 4 및
Hash[a4] # => {"apple"=>1, "banana"=>2, ["orange", "seedless"]=>3, "durian"=>nil}
- 변수 하기 - 평화변사 - 새용수탄a5
그리고.a6
몇 가지 다른 답변이 언급되었습니다. 포함 여부와 관계없이.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::[]
용사를 splat
으로 결합된a6
)는 호출하는 것과 같지 않습니다.Hash[a4]
:
Hash[*a6] # => ArgumentError: odd number of arguments for Hash
사전 배열,으로 미리플된배열다, 히중첩됨있수음여전얻로을으른방법a6
):
하지만 애초에 이것이 우리가 배열을 얻은 방법이라면 어떨까요?(즉, 와 비교할 수 있습니다.a1
입력 데이터였습니다. 이번에는 일부 데이터가 어레이 또는 다른 개체가 될 수 있습니다.)우리는 그것을 보았습니다.Hash[*a6]
작동하지는 않지만, 만약 우리가 마지막 요소(중요! 아래 참조)가 핵심으로 작용한 행동을 여전히 얻고 싶다면 어떨까요?nil
가치?
이러한 상황에서 키/값 쌍을 외부 배열의 요소로 되돌리는 방법은 다음과 같습니다.
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
}
(참고: 의 를 사용합니다.ap
여기서 구조를 더 쉽게 보여주기 위해, 개념적 요구 사항은 없습니다.)
그래서 그each_slice
불균형 플랫 입력에 대한 솔루션은 불균형 비트가 맨 끝에 있는 경우에만 작동합니다.
테이크아웃:
- 가능할 때마다 다음과 같이 입력을 설정합니다.
[key, value]
쌍(외부 배열의 각 항목에 대한 하위 배열). - 수 는 당이정그할수있면다렇게말로신,▁either▁when면있다수▁you▁do,▁that▁indeed▁can할당정.
#to_h
또는Hash::[]
둘 다 작동할 것입니다. - 당이할수없면다신,▁if.
Hash::[]
스플랫과 결합(*
)는 입력이 균형을 이루는 한 작동합니다. - 불균형하고 평평한 배열을 입력으로 사용할 경우, 이것이 합리적으로 작동하는 유일한 방법은 다음과 같은 경우입니다.
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]]
플랫한 다음 다음으로 변환합니다.
["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}
만약 당신이 이렇게 생긴 배열을 가지고 있다면 -
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
성능 및 메모리 할당 관련 문제는 여러 솔루션을 벤치마크한 단일 해시에 해시 배열을 매핑하는 Rails에 대한 답변을 확인하십시오.
reduce
/inject
어떤 방법을 사용하느냐에 따라 가장 빠른 솔루션 또는 가장 느린 솔루션이 될 수 있습니다.
숫자 값이 seq 인덱스라면 더 간단한 방법을 사용할 수 있습니다.코드 제출입니다. My Ruby는 약간 녹슬었습니다.
input = ["cat", 1, "dog", 2, "wombat", 3]
hash = Hash.new
input.each_with_index {|item, index|
if (index%2 == 0) hash[item] = input[index+1]
}
hash #=> {"cat"=>1, "wombat"=>3, "dog"=>2}
언급URL : https://stackoverflow.com/questions/39567/what-is-the-best-way-to-convert-an-array-to-a-hash-in-ruby
'source' 카테고리의 다른 글
NSData를 문자열로 변환하시겠습니까? (0) | 2023.06.01 |
---|---|
NSTime 변환 방법간격(초)(분) (0) | 2023.06.01 |
iPhone의 NS 문자열에서 HTML 태그 제거 (0) | 2023.06.01 |
다른 모델에 정의된 몽구스 데이터베이스의 스키마를 가져오는 방법 (0) | 2023.06.01 |
장고에서 "선택" 필드 옵션을 올바르게 사용하는 방법 (0) | 2023.06.01 |