Sum of hash value inside the array In ruby
data.each_with_object({}) do |g,h|
h.update(g[:lineItemKey]=>g) do |_k, old_hash, new_hash|
old_hash.merge(quantity: old_hash[:quantity] + new_hash[:quantity])
end
end.values
#=> [
# {:lineItemKey=>57, :sku=>"12GA-RIO", :name=>"12 Gauge",
# :quantity=>5, :unitPrice=>5.76},
# {:lineItemKey=>168, :sku=>"22LR-CAS-40-CPRN-50", :name=>"22 Long",
# :quantity=>2, :unitPrice=>7.6},
# {:lineItemKey=>236, :sku=>"300BLK-UNWD-CTC-220-BTHP-20",
# :name=>"300 BLK", :quantity=>1, :unitPrice=>31.2}
# ]
Note that the receiver of values
is
{
57=>{:lineItemKey=>57, :sku=>"12GA-RIO", :name=>"12 Gauge",
:quantity=>5, :unitPrice=>5.76},
168=>{:lineItemKey=>168, :sku=>"22LR-CAS-40-CPRN-50",
:name=>"22 Long", :quantity=>2, :unitPrice=>7.6},
236=>{:lineItemKey=>236, :sku=>"300BLK-UNWD-CTC-220-BTHP-20",
:name=>"300 BLK", :quantity=>1, :unitPrice=>31.2}
}
This uses the form of Hash#update (a.k.a merge!
) that employs a block to compute the values of keys that are present in both hashes being merged. Here that block is
do |_k, old_hash, new_hash|
old_hash.merge(quantity: old_hash[:quantity] + new_hash[:quantity])
end
See the doc for definitions of the three block variables. The underscore preceding k
(the common key) is intended tro signal to the reader that it is not used in the block calculation (a common convention which is often just the underscore alone).
Input
data =
[
{ :lineItemKey=>57, :sku=>"12GA-RIO",
:name=>"12 Gauge", :quantity=>4, :unitPrice=>5.76 },
{ :lineItemKey=>168, :sku=>"22LR-CAS-40-CPRN-50",
:name=>"22 Long", :quantity=>2, :unitPrice=>7.6 },
{ :lineItemKey=>57, :sku=>"12GA-RIO",
:name=>"12 Gauge", :quantity=>1, :unitPrice=>5.76 },
{ :lineItemKey=>236, :sku=>"300BLK-UNWD-CTC-220-BTHP-20",
:name=>"300 BLK", :quantity=>1, :unitPrice=>31.2 }
]
Code
p data.group_by { |x| x[:lineItemKey] }
.values
.map { |arr| arr.reduce { |h1, h2| h1.merge(h2) { |k, oldv, newv| k.eql?(:quantity) ? oldv += newv : oldv } } }
Output
[
{ :lineItemKey=>57, :sku=>"12GA-RIO",
:name=>"12 Gauge", :quantity=>5, :unitPrice=>5.76 },
{ :lineItemKey=>168, :sku=>"22LR-CAS-40-CPRN-50",
:name=>"22 Long", :quantity=>2, :unitPrice=>7.6 },
{ :lineItemKey=>236, :sku=>"300BLK-UNWD-CTC-220-BTHP-20",
:name=>"300 BLK", :quantity=>1, :unitPrice=>31.2 }
]