我想对数组中相同项的总值求和。
我有一个数组
[{"a"=>1},{"b"=>2},{"c"=>3},{"a"=>2},{"b"=>4}]
我希望得到结果
[{"a"=>3},{"b"=>6},{"c"=>3}]
哪种方法可以做到?
答案 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
中时才调用该块。之后,我们将哈希分解为哈希数组。