2015-05-24 119 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"]}