Ruby 如何使用不同的哈希值对数组中的值求和

Ruby 如何使用不同的哈希值对数组中的值求和,ruby,arrays,hash,Ruby,Arrays,Hash,我想对数组中相同项的总值求和 我有一个数组 [{"a"=>1},{"b"=>2},{"c"=>3},{"a"=>2},{"b"=>4}] 我想得到结果 [{"a"=>3},{"b"=>6},{"c"=>3}] 哪种方法可以做到这一点?有很多方法可以做到这一点。看到一些,甚至一些可能是不寻常的和/或不是特别有效的是很有启发性的 还有一种方法: arr = [{"a"=>1},{"b"=>2},{"c"=>3},{"a"=>

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

我有一个数组

[{"a"=>1},{"b"=>2},{"c"=>3},{"a"=>2},{"b"=>4}]
我想得到结果

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

哪种方法可以做到这一点?

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

还有一种方法:

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
,我们可以将
的块缩减为:

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

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

还有一种方法:

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
,我们可以将
的块缩减为:

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

然后你可以做:

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.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}]
或:


每当您不想以一对一的方式转换集合时,它就是
#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
中时,才会调用该块。然后,我们将散列分解为一个散列数组。

每当您希望以非一对一的方式转换集合时,它就是
#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
中时,才会调用该块。然后,我们将散列分解为一个散列数组。

可以按如下方式完成

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

可以按如下方式进行

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

您需要添加
.map{k,v{k=>v}}
或类似于结尾的内容,以将结果转换为指定的形式(哈希数组)。它应该生成:
[{“a”=>3},{“b”=>6},{“c”=>3}
而不是
{“b”=>6,“a”=>3,“c”=>3}
。我认为你需要像上面提到的@CarySwoveland那样做。你需要添加
.map{k,v{k=>v}}
或类似的东西来将结果转换成指定的形式(哈希数组)。它应该产生:
[{“a”=>3},{“b”=>6},{“c”=>3}
而不是
{b”=>6,“a”=>3,“c”=>3}
。我想你需要做一些像上面提到的@CarySwoveland那样的事情。
#每个带有_object的
都是我要找的,无论是否有人使用过。:-)但是你做到了,所以你节省了我的时间。您不需要
来创建一个
。(为什么?)。2.你不需要
;h
带有
每个带有对象的对象(这就是@Arup建议后者的原因)。3.
“arr”
是合适的名称吗?格式有了很大的改进。@CarySwoveland是的,没错。。这就是为什么如果我不是被迫的话,我不会经常使用
#inject
:P
#每个带有_对象的_
都是我要寻找的,无论是否有人使用过。:-)但是你做到了,所以你节省了我的时间。您不需要
来创建一个
。(为什么?)。2.你不需要
;h
带有
每个带有对象的对象(这就是@Arup建议后者的原因)。3.
“arr”
是合适的名称吗?格式有了很大的改进。@CarySwoveland是的,没错。。这就是为什么如果我不是被迫的话,我不会经常使用
#inject
:P