我想知道这个问题是否有一个很好的fold
(或地图,减少等)风格解决方案。
提供一系列购买(order_items)我想收集每个产品/ sku的总数。
示例集合:
[{sku: "A", price:10},
{sku: "B", price:5},
{sku: "C", price:2},
{sku: "B", price:5},
{sku: "A", price:10},
{sku: "B", price:5}]
得到结果:
{"A":20, "B":15, "C":2}
目前我这样做:
aggregate = order_items.each_with_object({}){|i,o|
o[i[:sku]] ||= 0
o[i[:sku]] += i[:price]
}
这给了我想要的东西,但我想知道是否有更优雅的方式来做到这一点?
显然,如果我预先过滤到单个SKU,我可以做一个经典reduce
即
# assuming sku is a flat array of values for a single sku type...
aggregate_sku = sku.reduce(:+)
但是,我不想预先过滤原始集合。有没有办法实现这一目标,还是我已经尽一切可能了?
感谢任何帮助。
编辑以增加问题的清晰度。如果您觉得有必要投票结束,请先发表评论,以便我澄清。
Subtext:我不确定map
,reduce
等是否具有我还不了解的功能(或更多可能的技术),谢谢。
答案 0 :(得分:2)
order_items = [
{sku: "A", price:10},
{sku: "B", price:5},
{sku: "C", price:2},
{sku: "B", price:5},
{sku: "A", price:10},
{sku: "B", price:5}
]
aggregate = order_items.each_with_object(Hash.new(0)) do |item, acc|
acc[ item[:sku] ] += item[:price]
end
--output:--
{"A"=>20, "B"=>15, "C"=>2}
答案 1 :(得分:1)
agg = order_items.group_by { |item| item.sku }
agg.each { |sku, items| agg[sku] = items.map(&:price).reduce(:+) }
答案 2 :(得分:1)
order_items.inject(Hash.new) {|hash, item| hash[item[:sku]] = (hash[item[:sku]] || 0) + item[:price]; hash}
它使用inject
代替each_with_object
,简化了聚合中的nil
个案。但它与你的问题大致相同。
请查看@ 7stud的答案,他确实以更好的方式处理0
默认值。