Group hashes by keys and sum the values
ar = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]p ar.inject{|memo, el| memo.merge( el ){|k, old_v, new_v| old_v + new_v}}#=> {"Vegetable"=>15, "Dry Goods"=>5}
Hash.merge
with a block runs the block when it finds a duplicate; inject
without a initial memo
treats the first element of the array as memo
, which is fine here.
Simply use:
array = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]array.inject{|a,b| a.merge(b){|_,x,y| x + y}}
ar = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]
While the Hash.merge
technique works fine, I think it reads better with an inject
:
ar.inject({}) { |memo, subhash| subhash.each { |prod, value| memo[prod] ||= 0 ; memo[prod] += value } ; memo }=> {"Dry Goods"=>5, "Vegetable"=>15}
Better yet, if you use Hash.new
with a default value of 0:
ar.inject(Hash.new(0)) { |memo, subhash| subhash.each { |prod, value| memo[prod] += value } ; memo }=> {"Dry Goods"=>5, "Vegetable"=>15}
Or if inject
makes your head hurt:
result = Hash.new(0)ar.each { |subhash| subhash.each { |prod, value| result[prod] += value } }result=> {"Dry Goods"=>5, "Vegetable"=>15}