2

我想知道fold这个问题是否有一个好的(或 map、reduce 等)风格的解决方案。

提供购买的集合 (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 进行预过滤,我可以做一个经典的reduceie。

# assuming sku is a flat array of values for a single sku type...
aggregate_sku = sku.reduce(:+)

但是,我不想预先过滤原始集合。有没有办法实现这一点,还是我已经尽了一切可能?

任何帮助表示赞赏。

编辑以增加问题的清晰度。如果您觉得需要投票结束,请先发表评论,以便我澄清。

潜台词:我不确定map, reduceetc 是否具有我还不了解的功能(或更可能的技术),谢谢。

4

3 回答 3

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}
于 2013-07-26T06:59:13.310 回答
1

使用Enumerable#group_by

agg = order_items.group_by { |item| item.sku }
agg.each { |sku, items| agg[sku] = items.map(&:price).reduce(:+) }
于 2013-07-26T05:03:02.480 回答
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以更好的方式处理默认值。

于 2013-07-26T05:12:04.943 回答