I'm wondering if there's a good fold
(or map, reduce etc.) style solution to this problem.
Give a collection of purchases (order_items) I want to gather the totals for each product/sku.
Example collection:
[{sku: "A", price:10},
{sku: "B", price:5},
{sku: "C", price:2},
{sku: "B", price:5},
{sku: "A", price:10},
{sku: "B", price:5}]
And get a result of:
{"A":20, "B":15, "C":2}
At present I do it like so:
aggregate = order_items.each_with_object({}){|i,o|
o[i[:sku]] ||= 0
o[i[:sku]] += i[:price]
}
Which gives me what I want, but I want to know if there's a more elegant way to do this?
Obviously, if I pre-filter to a single SKU I can do a classic reduce
ie.
# assuming sku is a flat array of values for a single sku type...
aggregate_sku = sku.reduce(:+)
However, I don't want to have to pre-filter the original collection. Is there a way to achieve this or am I already doing everything possible?
Any help is appreciated.
Edited to add clarity to the question. If you feel the need to vote to close, please post a comment first, so I can clarify.
Subtext: I'm not sure if map
, reduce
etc, has features (or more likely techniques) I don't yet understand, Thank you.
Using Enumerable#group_by
It uses
inject
instead ofeach_with_object
and simplifies thenil
case in the aggregation. But it's more or less the same as in your question.Please have a look at @7stud's answer, he does handles the
0
default value in a better way.