你如何在ruby中应用多个filter和总和?

我有一个Order类型的对象数组

Order :status :amount 

状态可以预付后付取消

我想获得每种状态的金额总和。 你是如何用ruby做到的?

示例:如果我有五个订单

 O1 - postpaid - 100 O2 - prepaid - 10 O3 - prepaid - 15 O4 - cancelled - 20 O5 - cancelled - 45 

输出应该是一个看起来像这样的地图

 {postpaid: 100, prepaid: 25, cancelled: 65} 

如果

 a = [[:post, 100],[:pre, 10], [:pre, 15],[:canc, 20],[:canc, 45]] 

有很多人想要获得这笔钱。 这是两个。

使用Enumerable#each_with_object

该对象是一个哈希值,使用默认值零进行初始化:

 a.each_with_object(Hash.new(0)) { |(type,amt),h| h[type] += amt } #=> {:post=>100, :pre=>25, :canc=>65} 

以下是步骤:

 enum = a.each_with_object(Hash.new(0)) #=> # 

我们可以通过将枚举器转换为数组来查看由Enumerator#each传递到块中的枚举器的内容:

 enum.to_a #=> [[[:post, 100], {}], [[:pre, 10], {}], [[:pre, 15], {}], # [[:canc, 20], {}], [[:canc, 45], {}]] 

我们可以使用Enumerator#next逐步完成计算:

 (type,amt),h = enum.next #=> [[:post, 100], {}] type #=> :post amt #=> 100 h #=> {} h[type] += amt #=> h[type] = h[type] + amt #=> h[:post] = h[:post] + 100 #=> h[:post] = 0 + 100 # h[:post] on right set to default value #=> h[:post] = 100 

 (type,amt),h = enum.next #=> [[:pre, 10], {:post=>100}] h[type] += amt #=> 10 (type,amt),h = enum.next #=> [[:pre, 15], {:post=>100, :pre=>10}] h[type] += amt #=> 25 (type,amt),h = enum.next #=> [[:canc, 20], {:post=>100, :pre=>25}] h[type] += amt #=> 20 (type,amt),h = enum.next #=> [[:canc, 45], {:post=>100, :pre=>25, :canc=>20}] h[type] += amt #=> 65 h #=> {:post=>100, :pre=>25, :canc=>65} 

使用Enumerable#group_by

 Hash[a.group_by(&:first) .values .map { |b| [b.first.first, b.reduce(0) {|tot,(_,amt)| tot+amt}]}] #=> {:post=>100, :pre=>25, :canc=>65} 

步骤:

 h = a.group_by(&:first) #=> {:post=>[[:post, 100]], # :pre=> [[:pre, 10], [:pre, 15]], # :canc=>[[:canc, 20], [:canc, 45]]} c = h.values #=> [[[:post, 100]], # [[:pre, 10], [:pre, 15]], # [[:canc, 20], [:canc, 45]]] 

map首先将c的第一个元素(包含一个元素的数组,数组[:post, 100] )传递给块并将其分配给块变量:

 b = [[:post, 100]] [b.first.first, b.reduce(0) {|tot,(_,amt)| tot+amt}] #=> [[:post, 100].first, [[:post, 100]].reduce(0) {|tot,(_,amt)| tot+amt}] #=> [:post, 100] 

map然后将c的第二个元素传递给块:

 b = [[:pre, 10], [:pre, 15]] [b.first.first, b.reduce(0) {|tot,(_,amt)| tot+amt}] #=> [:pre, 25] 

等等。 在将c所有元素传递给块之后,映射的值将作为数组返回:

 d = [[:post, 100], [:pre, 25], [:canc, 65]] 

最后一步是将其转换为哈希:

 Hash[d] #=> {:post=>100, :pre=>25, :canc=>65} 

或者在Ruby 2.0+中:

 d.to_h #=> {:post=>100, :pre=>25, :canc=>65}