2017-04-08 166 views
1

我有一個約860項的數組,我想把它變成一個散列,數組結構是(Key1,value1,value2,value3,Key2,value1,value 2,價值3 ...........等等)除了在現實生活中看起來像(彼得,150,39,345,約翰,123,450,402,瑪麗,145,345,506。 ...........)。原來這些是我一起調換過的四個數組,所以我可以從4個獨立數組開始達到相同的最終目標。將數組拆分成哈希

我想

Hash {Peter=> [150, 39, 345], John=>[123,450,402], Mary => [145,345,506] etc etc 

我覺得應該是一個不錯的整潔的方式做到這一點,但它躲開我,可能是因爲我不知道足夠的紅寶石。

+0

如果數值數組都是一樣的長度不能你只是迭代和每個項目添加到相應的哈希值的條目?你並沒有真正說明原始數組是什麼,但它似乎更容易跳過數組連接。 –

回答

1

如果您知道數據始終處於套4:

l = ['Peter', 150, 39, 345, 'John', 123, 450, 402, 'Mary', 145, 345, 506] 
h = {} 
l.each_slice(4).each do |chunk| 
    h[chunk[0]] = chunk[1..chunk.length] 
end 

或者,如果你知道的鑰匙總是字符串:

l = ['Peter', 150, 39, 345, 'John', 123, 450, 402, 'Mary', 145, 345, 506] 
h = {} 
current_key = "" 
l.each do |item| 
    if item.is_a? String 
     current_key = item 
     h[item] = [] 
    else 
     h[current_key] << item 
    end 
end 

基本上,你需要找出如何切片適當的數組,然後循環。

此外,如果你已經有了他們,你可以很容易地只是單獨的數組:

array_1 = ['Peter', 150, 39, 345] 
array_2 = ['John', 123, 450, 402] 
array_3 = ['Mary', 145, 345, 506] 
h = {}  

[array_1,array_2, array_3].each do |a| 
    h[a[0]] = a[1:a.length] 
end 

# One line version: 
[array_1,array_2, array_3].map{|a| h[a[0]] = a[1..a.length]} 

這一點我要說的是最乾淨的方法。

4

另一種方式:

l = ['Peter', 150, 39, 345, 'John', 123, 450, 402, 'Mary', 145, 345, 506] 

Hash[*l.each_slice(4).flat_map { |a, *b| [a, b] }] 
#=> {"Peter"=>[150, 39, 345], 
# "John" =>[123, 450, 402], 
# "Mary" =>[145, 345, 506]} 

如果你已經有數組,解決方案會更加簡單:

arrays = [array_1, array_2, array_3] 
Hash[*arrays.flat_map {|a, *b| [a, b]} ] 
#=> {"Peter"=>[150, 39, 345], "John"=>[123, 450, 402], "Mary"=>[145, 345, 506]} 
3
arr = ['Peter', 150, 39, 345, 'John', 123, 450, 'Mary', 145, 345, 506, 222] 

arr.slice_before {|a| String === a }. 
    each_with_object({}) {|(f,*rest), h| h[f] = rest} 
    #=> {"Peter"=>[150, 39, 345], "John"=>[123, 450], "Mary"=>[145, 345, 506, 222]} 

Enumerable#slice_before用Ruby V2.3首次亮相。人們可以使用Enumerable#slice_when,這在v2.2中是新的。

這裏有幾個方法可用於早期版本的Ruby。

arr.chunk { |e| String === e }. 
    each_slice(2). 
    with_object({}) { |((_,(k)),(_,v)), h| h[k] = v } 

a = [] 
enum = arr.to_enum 
loop do 
    o = enum.next 
    (String === o) ? a << [o,[]] : a.last.last << o 
end 
Hash[a] 
1

原件這些都是我曾經一起調換四個陣列,這樣我就可以通過4個獨立的陣列開始達​​到同樣的最終目標。

我假設你有這樣的事情入手:

a = ["Peter", "John", "Mary"] 
b = [150, 123, 145] 
c = [39, 450, 345] 
d = [345, 402, 506] 

您可以通過zip結合「價值」的數組:

values = b.zip(c, d) 
#=> [[150, 39, 345], [123, 450, 402], [145, 345, 506]] 

,並通過添加「鍵」陣另一個zip

a.zip(values) 
#=> [["Peter", [150, 39, 345]], ["John", [123, 450, 402]], ["Mary", [145, 345, 506]]] 

這已經是正確的結構,所以我們可以叫to_h

a.zip(values).to_h 
#=> {"Peter"=>[150, 39, 345], "John"=>[123, 450, 402], "Mary"=>[145, 345, 506]} 

當然,你並不需要中間變量,a.zip(b.zip(c, d)).to_h返回相同的結果。

+1

或者您可以'轉置'而不是第二個'zip':'哈希[a.zip([b,c,d] .transpose)]' – Ilya

+0

...或'[a,b,c,d]。 transpose.each_with_object({}){|(k,* v),h | h [k] = v}'。 –

0

試試這個

l = ['Peter', 150, 39, 345, 'John', 123, 450, 402, 'Mary', 145, 345, 506] 

l.each_slice(4).to_a.inject({}){|acc, temp| acc[temp.first]=temp.last(3); acc} 

#=>{"Peter"=>[150, 39, 345], "John"=>[123, 450, 402], "Mary"=>[145, 345, 506]}