2015-05-24 171 views
1

我有紅寶石兩個數組保留了重複鍵的鍵值對:合併兩個數組時,哈希

array_one = ["farmer_joe", "farmer_judy", "farmer_crazy_eyes", "farmer_joe"] 

array_two = ["pigs", "chickens", "elephants", "cows"] 

如果我使用壓縮功能我失去了重複的值,密鑰對農民喬。

hash_one = Hash[array_one.zip array_two] 

=> {"farmer_joe"=>"cows", "farmer_judy"=>"chickens", "farmer_crazy_eyes"=>"elephants"} 

理想我想一個可以讓我以一記漂亮的紅寶石味的ONELINE方法克服這一點。也許像這樣合併重複鍵並將它們的值添加到數組。

hash_one = Hash[array_one.super_special_zip array_two] 

=> {"farmer_joe"=>["pigs","cows"], "farmer_judy"=>["chickens"], "farmer_crazy_eyes"=>["elephants"]} 

是否有這樣的super_special_zip方法?還是有一個很好的理由,爲什麼這是一個傻瓜差事呢?

+0

'array_one.zip array_two'不輸重複,變成一個哈希不結果。 – steenslag

回答

3

有三種標準的做法。

a1 = ["farmer_joe", "farmer_judy", "farmer_crazy_eyes", "farmer_joe"] 
a2 = ["pigs", "chickens", "elephants", "cows"] 
pairs = a1.zip(a2) # or [a1,a2].transpose 
    #=> [["farmer_joe", "pigs"], ["farmer_judy", "chickens"], 
    # ["farmer_crazy_eyes", "elephants"], ["farmer_joe", "cows"]] 

1.使用Hash.new創建散列與一個空數組

pairs.each_with_object(Hash.new { |h,k| h[k]=[] }) { |(f,l),h| h[f] << l } 
    # => {"farmer_joe"=>["pigs", "cows"], "farmer_judy"=>["chickens"], 
    #  "farmer_crazy_eyes"=>["elephants"]} 

這方面的一個變體(其傾向於稍快)的缺省值是:

pairs.each_with_object({}) { |(f,l),h| (h[f] ||= []) << l } 

2.使用Hash#update(又名合併!)的形式,它需要一個塊來確定ke的值目前在這兩個哈希YS被合併

pairs.each_with_object({}) { |(f,l),h| h.update(f=>[l]) { |_,o,n| o+n } } 
    #=> {"farmer_joe"=>["pigs", "cows"], "farmer_judy"=>["chickens"], 
    # "farmer_crazy_eyes"=>["elephants"]} 

3.使用Enumerable#group_by

h = pairs.group_by(&:first) 
    #=> {"farmer_joe"=>[["farmer_joe", "pigs"], ["farmer_joe", "cows"]], 
    # "farmer_judy"=>[["farmer_judy", "chickens"]], 
    # "farmer_crazy_eyes"=>[["farmer_crazy_eyes", "elephants"]]} 
h.keys.each { |k| h[k] = h[k].map(&:last) } 
h 
    #=> {"farmer_joe"=>["pigs", "cows"], "farmer_judy"=>["chickens"], 
    # "farmer_crazy_eyes"=>["elephants"]} 

還有許多其他的最後兩行,其中之一是:

h.merge(h) { |*_,v| v.map(&:last) } 
2

的一種方式做到這一點

array_one = ["farmer_joe", "farmer_judy", "farmer_crazy_eyes", "farmer_joe"] 
array_two = ["pigs", "chickens", "elephants", "cows"] 

hash_one = {} 

array_one.each_with_index do |farmer,i| 
    if hash_one.has_key?(farmer) 
     hash_one[farmer] << array_two[i] 
    else 
     hash_one[farmer] = [array_two[i]] 
    end 
end 

hash_one # => {"farmer_joe"=>["pigs", "cows"], "farmer_judy"=>["chickens"], "farmer_crazy_eyes"=>["elephants"]} 
+0

類似於上面,我會說這有點更清楚,但我喜歡卡里的單線。如果我無法獲得以'super_special_zip'方法構建的魔法,上面的方法可能會奏效。非常感謝您的貢獻! – Huw

+0

這是更可讀和簡單的+1 – Ashik

1

而另一種方式來做到這將是(無軌)

a1 = ["farmer_joe", "farmer_judy", "farmer_crazy_eyes", "farmer_joe"] 
a2= ["pigs", "chickens", "elephants", "cows"] 

a1.zip(a2).group_by(&:first).map{|key, value| [key, value.map(&:last)]}.to_h 

# => {"farmer_joe"=>["pigs", "cows"], "farmer_judy"=>["chickens"], "farmer_crazy_eyes"=>["elephants"]}