[英]Ruby combining hashes in an array based on one hash value
I have an array of hashes that looks like: 我有一系列的哈希,看起来像:
[
{"id"=>1, "name"=>"Batman", "net_worth"=>100, "vehicles"=>2},
{"id"=>1, "name"=>"Batman", "net_worth"=>100, "vehicles"=>2},
{"id"=>2, "name"=>"Superman", "net_worth"=>100, "vehicles"=>2},
{"id"=>3, "name"=>"Wonderwoman", "net_worth"=>100, "vehicles"=>2}
]
I'd like to combine hashes based on the id value while preserving it, preserve the name, and sum the net_worth and vehicles values. 我想在保留ID的基础上结合基于id的哈希值,保留名称,并对net_worth和Vehicle值求和。
So the final array would look like: 因此,最终数组如下所示:
[
{"id"=>1, "name"=>"Batman", "net_worth"=>200, "vehicles"=>4},
{"id"=>2, "name"=>"Superman", "net_worth"=>100, "vehicles"=>2},
{"id"=>3, "name"=>"Wonderwoman", "net_worth"=>100, "vehicles"=>2}
]
Here is solution of your problem. 这是您的问题的解决方案。 As you can see you should group rows by id and name, then calculate sum of other values and build result: 如您所见,您应该按ID和名称对行进行分组,然后计算其他值的总和并生成结果:
rows = [
{"id"=>1, "name"=>"Batman", "net_worth"=>100, "vehicles"=>2},
{"id"=>1, "name"=>"Batman", "net_worth"=>100, "vehicles"=>2},
{"id"=>2, "name"=>"Superman", "net_worth"=>100, "vehicles"=>2},
{"id"=>3, "name"=>"Wonderwoman", "net_worth"=>100, "vehicles"=>2}
]
groups = rows.group_by {|row| [row['id'], row['name']] }
result = groups.map do |key, values|
id, name = *key
total_net_worth = values.reduce(0) {|sum, value| sum + value['net_worth'] }
total_vehicles = values.reduce(0) {|sum, value| sum + value['vehicles'] }
{ "id" => id, "name" => name, "net_worth" => total_net_worth, "vehicles" => total_vehicles }
end
p result
Here are two ways of doing it that work with any number of key-value pairs, and do not depend on the names of keys (other than "id"
and "name"
, of course, which are part of the specification). 这是两种可与任意数量的键-值对一起使用且不依赖于键名的方法(当然, "id"
和"name"
除外,它们是规范的一部分)。
Using update
使用update
This is a way that uses the form of Hash#update (aka merge!
) that employs a block to determine the values of keys that are present in both hashes: 这是一种使用Hash#update (也称为merge!
)形式的方法,该方法采用一个块来确定两个哈希中都存在的键的值:
arr = [
{"id"=>1, "name"=>"Batman", "net_worth"=>100, "vehicles"=>2},
{"id"=>1, "name"=>"Batman", "net_worth"=>100, "vehicles"=>2},
{"id"=>2, "name"=>"Superman", "net_worth"=>100, "vehicles"=>2},
{"id"=>3, "name"=>"Wonderwoman", "net_worth"=>100, "vehicles"=>2}
]
arr.each_with_object({}) { |g,h|
h.update(g["id"]=>g.dup) { |_,oh,nh|
oh.update(nh) { |k,ov,nv|
(['id','name'].include?(k)) ? ov : ov+nv } } }.values
#=> [{"id"=>1, "name"=>"Batman", "net_worth"=>200, "vehicles"=>4},
# {"id"=>2, "name"=>"Superman", "net_worth"=>100, "vehicles"=>2},
# {"id"=>3, "name"=>"Wonderwoman", "net_worth"=>100,"vehicles"=>2}]
Using group_by
使用group_by
This could also be done by using Enumerable#group_by , as @maxd has done, but the following is a more compact and general implementation: 也可以使用Enumerable#group_by来完成,就像@maxd一样,但是以下是更紧凑和更通用的实现:
arr.map(&:dup).
group_by { |row| row['id'] }.
map { |_,arr|
arr.reduce { |h, g|
(g.keys - ['id','name']).each { |k| h[k] += g[k] }; h } }
#=> [{"id"=>1, "name"=>"Batman", "net_worth"=>200, "vehicles"=>4},
# {"id"=>2, "name"=>"Superman", "net_worth"=>100, "vehicles"=>2},
# {"id"=>3, "name"=>"Wonderwoman", "net_worth"=>100,"vehicles"=>2}]
arr.map(&:dup)
is to avoid mutating arr
. arr.map(&:dup)
是为了避免对arr
进行变异。 I used reduce
without an argument to avoid the need for copying the key-value pairs having keys "id"
and "name"
. 我使用了不带参数的reduce
来避免复制具有键"id"
和"name"
的键值对。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.