我想总结数组中相同项的总数。如何使用不同的散列求和数组中的值
我有一个数组作为
[{"a"=>1},{"b"=>2},{"c"=>3},{"a"=>2},{"b"=>4}]
我想要得到的结果作为
[{"a"=>3},{"b"=>6},{"c"=>3}]
哪一种方法可以做到这一点?
我想总结数组中相同项的总数。如何使用不同的散列求和数组中的值
我有一个数组作为
[{"a"=>1},{"b"=>2},{"c"=>3},{"a"=>2},{"b"=>4}]
我想要得到的结果作为
[{"a"=>3},{"b"=>6},{"c"=>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}]
有很多方法可以做到这一点。看到一些甚至是一些可能不寻常和/或不是特别有效的东西是有益的。
这里是另一种方式:
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 }
要在不是一比一的方式来转换集合每一次,它是#reduce
工作。对于一对一转换,我们使用#map
。
array.reduce({}) { |h, acc| acc.merge(h) {|_k, o, n| o+n } }.zip.map(&:to_h)
# => [{"b"=>6}, {"a"=>3}, {"c"=>3}]
在这里,我们使用与初始值{}
,其被传递到块作为acc
参数减少,然后我们使用#merge
具有手动“解决冲突”。这意味着仅当我们试图合并的密钥已经存在于方法接收器acc
中时才会调用该块。之后,我们将哈希分解为哈希数组。
你需要添加'。{{| k,v | {k => v}}'或者类似于结尾的东西,将结果转换为指定的形式(散列数组)。 – 2014-10-02 06:55:49
它应该产生:'[{“a”=> 3},{“b”=> 6},{“c”=> 3}]'不是'{“b”=> 6,“a”=> 3,“c”=> 3}'。我认为你需要做一些像@CarySwoveland提到的事情。 – Surya 2014-10-02 07:02:01
这也是一个好方法。谢谢。 – 2014-10-02 09:50:24
它可以如下
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}]
'#each_with_object'就是我要找如果使用或不使用任何一个来完成。 :-)但是你做到了,所以你节省了我的时间..:P +1 – 2014-10-02 08:05:45
1.你不需要'to_a'。 (为什么?)。 2.你不需要'; h'与'each_with_object'(这就是@Arup建议后者的原因)。 3.“arr”是一个合适的名字吗?该格式大大改善。 – 2014-10-02 15:26:44
@CarySwoveland是的正是..这就是为什么我不使用'#注入',如果我不被迫.. .. P – 2014-10-02 15:33:21