[英]Merge an array of hashes in Ruby and count the same key
I have some data in this format 我有这种格式的一些数据
[{
"_id" => "20",
"value" => 1
}, {
"_id" => "19",
"value" => 1
}, {
"_id" => nil,
"value" => 8
}, {
"_id" => "27",
"value" => 1
}, {
"_id" => "25",
"value" => 3
}, {
"_id" => "28",
"value" => 1
}]
I want to merge the same values with "_id" key and sum the "value" values. 我想将相同的值与“_id”键合并,并将“值”值相加。
Desire output 欲望输出
[{
"_id" => "20",
"value" => 1
}, {
"_id" => "19",
"value" => 2
}, {
"_id" => nil,
"value" => 8
}, ...]
There is an elegant way to do this? 有一种优雅的方式来做到这一点?
I have tried with two loops but I think that is not the best way to do it. 我试过两个循环,但我认为这不是最好的方法。
As with most things in Ruby, a trip to the Enumerable
documentation turns up the group_by
method which can help group things together by some arbitrary criteria. 与Ruby中的大多数内容一样,访问Enumerable
文档会调出group_by
方法,该方法可以通过某些任意标准帮助将事物组合在一起。 Combine that with something that does the sums and you get this: 将它与总和的东西结合起来就可以得到:
v.group_by do |e|
e['_id']
end.map do |id, list|
{
'_id' => id,
'value' => list.inject(0) { |sum, e| sum + e['value'] }
}
end
# => [{"_id"=>"20", "value"=>1}, {"_id"=>"19", "value"=>2}, {"_id"=>nil, "value"=>28},
# {"_id"=>"27", "value"=>1}, {"_id"=>"25", "value"=>3}, {"_id"=>"28", "value"=>1},
# {"_id"=>"23", "value"=>1}, {"_id"=>"16", "value"=>1}, {"_id"=>"18", "value"=>2},
# {"_id"=>"22", "value"=>2}]
arr = [{ "_id" => "20", "value" => 1 },
{ "_id" => "19", "value" => 1 },
{ "_id" => nil, "value" => 8 },
{ "_id" => "20", "value" => 1 },
{ "_id" => "25", "value" => 3 },
{ "_id" => "19", "value" => 1 },
]
h = arr.each_with_object(Hash.new(0)) { |g,h| h[g["_id"]] += g["value"] }
#=> {"20"=>2, "19"=>2, nil=>8, "25"=>3}
If you instead want to return an array of hashes with unique values for "_id"
and the values of "value"
updated, you could first compute h
above, then 如果你想要返回一个具有"_id"
唯一值的哈希数组并更新"value"
的值,你可以先计算h
,然后
arr.uniq { |g| g["_id"] }.map { |g| g.update("_id"=>h[g["_id"]]) }
#=> [{"_id"=>"20", "value"=>2}, {"_id"=>" 19", "value"=>2},
# {"_id"=>nil, "value"=>8}, {"_id"=>"25", "value"=>3}]
This uses the methods Array#uniq with a block, Enumerable#map and Hash#update (aka merge!
). 这使用方法Array#uniq和一个块, Enumerable #map和Hash #update (aka merge!
)。
Alternatively, you could write the following. 或者,您可以编写以下内容。
arr.each_with_object({}) { |g,h|
h.update(g["_id"]=>g) { |_,o,n| o.merge("value"=>o["value"]+n["value"]) } }.values
#=> [{"_id"=>"20", "value"=>2}, {"_id"=>" 19", "value"=>2},
# {"_id"=>nil, "value"=>8}, {"_id"=>"25", "value"=>3}]
Again, I've used Hash#update
, but this time I have employed a block to determine the values of keys that are present in both hashes being merged. 同样,我使用了Hash#update
,但这次我使用了一个块来确定两个哈希中合并的键的值。 See also Enumerable#each_with_object and Hash#merge . 另请参见Enumerable#each_with_object和Hash #incoration 。 Note that, as arguments, (k=>v)
is shorthand for ({ k=>v })
. 注意,作为参数, (k=>v)
是({ k=>v })
简写。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.