Group hashes by keys and sum the values Group hashes by keys and sum the values ruby ruby

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}