将两个数组合并到散列

时间:2015-05-24 12:43:56

标签: ruby

我在ruby中有两个数组:

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

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

如果我使用zip函数,我会丢失重复值,即Farmer Joe的密钥对。

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方法?或者有一个很好的理由为什么这首先是傻瓜差事?

3 个答案:

答案 0 :(得分: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(也称为merge!)的形式,它采用一个块来确定合并的两个哈希中存在的键的值

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) }

答案 1 :(得分: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"]}

答案 2 :(得分: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"]}