这是我的数组:
collection
=> [{:title=>"Movie A", :studio=>"Alpha Films", :worldwide_gross=>10},
{:title=>"Movie B", :studio=>"Alpha Films", :worldwide_gross=>30},
{:title=>"Movie C", :studio=>"Omega Films", :worldwide_gross=>30}]
我的目标是返回每个工作室的总和:
#=> :studio => "Alpha Films", :worldwide_gross => 40
#=> :studio => "Omega Films", :worldwide_gross => 30
到目前为止,我已经提出了以下逻辑,但它只一次性返回所有工作室的总和:
gross_result = collection.sum {|h| h[:worldwide_gross]}
result #=> 70
您可以使用Enumerable#group_by
和Hash#transform_values
然后像以前一样求和:
collection.group_by { |h| h[:studio] }.transform_values { |v| v.sum{ |h| h[:worldwide_gross] } }
#=> {"Alpha Films"=>40, "Omega Films"=>30}
group_by
返回的位置:
collection.group_by { |h| h[:studio] }
#=> {"Alpha Films"=>[{:title=>"Movie A", :studio=>"Alpha Films", :worldwide_gross=>10}, {:title=>"Movie B", :studio=>"Alpha Films", :worldwide_gross=>30}], "Omega Films"=>[{:title=>"Movie C", :studio=>"Omega Films", :worldwide_gross=>30}]}
此解决方案首先创建一个哈希,其键是collection
中g
的所有哈希值的g[:studio]
的唯一值,其值是给定键的所有g
的g[:worldwide_gross]
的总和。然后将该哈希转换为所需的哈希。
collection.each_with_object(Hash.new(0)) do |g,h|
h[g[:studio]] += g[:worldwide_gross]
end.map { |k,v| { studio: k, worldwide_gross: v } }
#=> [{:studio=>"Alpha Films", :worldwide_gross=>40},
# {:studio=>"Omega Films", :worldwide_gross=>30}]
这两个步骤如下。
h = collection.each_with_object(Hash.new(0)) do |g,h|
h[g[:studio]] += g[:worldwide_gross]
end
#=> {"Alpha Films"=>40, "Omega Films"=>30}
h.map { |k,v| { studio: k, worldwide_gross: v } }
#=> [{:studio=>"Alpha Films", :worldwide_gross=>40},
# {:studio=>"Omega Films", :worldwide_gross=>30}]
h
的计算(有时称为计数哈希)采用 Hash::new 的形式,它定义了一个默认值(此处为零),该默认值是h[k]
为哈希返回的值,h
在没有键k
时如此定义h
。它等效于以下内容。
h = collection.each_with_object({}) do |g,h|
h[g[:studio]] = (h[g[:studio]] || 0) + g[:worldwide_gross]
end
如果h
没有密钥g[:studio]
则h[g[:studio]] #=> nil
,所以h[g[:studio]] || 0 #=> 0
。如果h
有一个键g[:studio]
(其值不是nil
或false
),则h[g[:studio]] || 0 #=> h[g[:studio]]
。
您可以使用reduce方法
result = a.group_by { |h| h[:studio] }.values.map do |arr|
arr.reduce do |h1, h2|
h1.merge(h2) do |k, v1, v2|
k.eql?(:worldwide_gross) ? (v1 + v2) : v1
end
end
end
p 结果
[{:partner_name=>"company 1", :partner_id=>787, :value=>3}, {:partner_name=>"company 2", :partner_id=>768, :value=>1}, {:partner_name=>"company 3", :partner_id=>769, :value=>1}]