Ruby在哈希集合中聚合选择性值

时间:2017-07-03 14:03:44

标签: ruby-on-rails ruby hash

我有一系列哈希,键是国家,值是天数。

我想在哈希值上进行汇总,并对相同国家/地区的值进行求和。

数组看起来像countries = [{"Country"=>"Brazil", "Duration"=>731/1 days}, {"Country"=>"Brazil", "Duration"=>365/1 days}]

我希望这可以返回以下内容:[{"Country" => "Brazil", "Duration"=>1096/1 days}]

我在SO like this one

上尝试了其他问题
countries.inject{|new_h, old_h| new_h.merge(old_h) {|_, old_v, new_v| old_v + new_v}}

制作{"Country"=>"BrazilBrazil", "Duration"=>1096/1 days}

有没有办法有选择地只合并特定的值?

2 个答案:

答案 0 :(得分:4)

这使用Hash::new的形式创建一个带有默认值的空哈希(此处为0)。对于以这种方式创建的哈希h,如果哈希没有键h[k]k将返回默认值。哈希未被修改。

countries = [{"Country"=>"Brazil",    "Duration"=>"731/1 days"},
             {"Country"=>"Argentina", "Duration"=>"123/1 days"},
             {"Country"=>"Brazil",    "Duration"=>"240/1 days"},
             {"Country"=>"Argentina", "Duration"=>"260/1 days"}]

countries.each_with_object(Hash.new(0)) {|g,h| h[g["Country"]] += g["Duration"].to_i }.
  map { |k,v| { "Country"=>k, "Duration"=>"#{v}/1 days" } }
    #=> [{"Country"=>"Brazil",    "Duration"=>"971/1 days"},
    #    {"Country"=>"Argentina", "Duration"=>"383/1 days"}]

第一个散列传递给块并分配给块变量g

g = {"Country"=>"Brazil", "Duration"=>"731/1 days"}

此时h #=> {}。然后我们计算

h[g["Country"]] += g["Duration"].to_i
  #=> h["Brazil"] += "971/1 days".to_i
  #=> h["Brazil"] = h["Brazil"] + 971
  #=> h["Brazil"] = 0 + 971 # h["Brazil"]

有关"971/1 days".to_i返回971的原因的说明,请参阅String#to_i

相等右侧的

h["Brazil"]返回默认值0,因为h尚未(还)有一个键"Brazil"。请注意,右侧的h["Brazil"]h.[]("Brazil")的语法糖,而左侧是h.[]=(h["Brazil"] + 97)的语法糖。当散列没有给定键时,它返回默认值Hash#[]。其余步骤类似。

答案 1 :(得分:2)

您可以按如下方式更新您的代码:

countries.inject do |new_h, old_h| 
    new_h.merge(old_h) do |k, old_v, new_v|
        if k=="Country" then old_v else old_v + new_v end
    end 
end
#  => {"Country"=>"Brazil", "Duration"=>1096} 

您基本上使用k(用于)参数来切换不同的合并策略。