如何对具有不同散列的数组中的值求和

时间:2014-10-02 05:46:22

标签: ruby arrays hash

我想对数组中相同项的总值求和。

我有一个数组

[{"a"=>1},{"b"=>2},{"c"=>3},{"a"=>2},{"b"=>4}]

我希望得到结果

[{"a"=>3},{"b"=>6},{"c"=>3}]

哪种方法可以做到?

4 个答案:

答案 0 :(得分:3)

如果:

array = [{"a"=>1},{"b"=>2},{"c"=>3},{"a"=>2},{"b"=>4}]

然后你可以这样做:

array.inject(Hash.new{|h,k| h[k] = 0})
      { |h, a| k, v = a.flatten;  h[k] += v; h }.
      map{|arr| Hash[*arr] }
#=> [{"a"=>3}, {"b"=>6}, {"c"=>3}]

或:

array.each_with_object(Hash.new{|h,k| h[k] = 0})
      { |a, h| k, v = a.flatten;  h[k] += v }.
      map{|arr| Hash[*arr] }
#=> [{"a"=>3}, {"b"=>6}, {"c"=>3}]

答案 1 :(得分:2)

可以按照以下方式完成

array.group_by { |h| h.keys.first }.
values.
map {|x| x.reduce({}) { |h1, h2| h1.merge(h2) { |_, o, n| o + n } }

#=> [{"a"=>3}, {"b"=>6}, {"c"=>3}]

答案 2 :(得分:1)

有很多方法可以做到这一点。看到一些,甚至一些可能不寻常和/或不是特别有效的一些是有益的。

这是另一种方式:

arr = [{"a"=>1},{"b"=>2},{"c"=>3},{"a"=>2},{"b"=>4}]

arr.flat_map(&:keys)
   .uniq
   .map { |k| { k=>arr.reduce(0) { |t,g| t + (g.key?(k) ? g[k] : 0) } } } 
  #=> [{"a"=>3}, {"b"=>6}, {"c"=>3}]

nil.to_i => 0开始,我们可以将reduce的块写为:

   { |t,g| t+g[k].to_i }

答案 3 :(得分:1)

每次你想以一对一的方式转换一个集合时,它都是#reduce的工作。对于一对一转换,我们使用#map

array.reduce({}) { |h, acc| acc.merge(h) {|_k, o, n| o+n } }.zip.map(&:to_h)
# => [{"b"=>6}, {"a"=>3}, {"c"=>3}]

这里我们使用reduce初始值{},它作为acc参数传递给块,然后我们使用#merge手动“冲突解决”。这意味着仅当我们尝试合并的键已经存在于方法接收器acc中时才调用该块。之后,我们将哈希分解为哈希数组。