如何在Ruby中对数组中对象的属性求和

时间:2012-06-30 09:12:24

标签: ruby arrays object sum inject

据我所知,为了在Ruby中对数组元素求和,可以使用inject方法,即

array = [1,2,3,4,5];
puts array.inject(0, &:+) 

但是如何对对象数组中对象的属性求和,例如。

有一个对象数组,每个对象都有一个属性“cash”。所以我想将他们的现金余额总计为一个。有点像...

array.cash.inject(0, &:+) # (but this doesn't work)

我意识到我可能会制作一个仅由物业现金组成的新阵列,并总结一下,但如果可能的话,我正在寻找一种更清洁的方法!

7 个答案:

答案 0 :(得分:59)

array.map(&:cash).inject(0, &:+)

array.inject(0){|sum,e| sum + e.cash }

答案 1 :(得分:48)

在Ruby On Rails中,您也可以尝试:

array.sum(&:cash)

它是注射业务的捷径,对我来说似乎更具可读性 http://api.rubyonrails.org/classes/Enumerable.html

答案 2 :(得分:9)

#reduce占用一个块(&:+是创建执行+)的proc / block的快捷方式。这是做你想做的事的一种方式:

array.reduce(0) { |sum, obj| sum + obj.cash }

答案 3 :(得分:3)

最简洁的方式:

array.map(&:cash).sum

如果地图中生成的数组有nil项:

array.map(&:cash).compact.sum

答案 4 :(得分:1)

无需使用初始注入和加号操作可以更短

array.map(&:cash).inject(:+)

答案 5 :(得分:1)

如果求和的起始值为0,则单独的sum与inject:

相同
array.map(&:cash).sum

我更喜欢块版本:

array.sum { |a| a.cash }

因为符号的Proc通常太有限(没有参数等)。

(需要Active_Support)

答案 6 :(得分:1)

这里有一些有趣的基准

array = Array.new(1000) { OpenStruct.new(property: rand(1000)) }

Benchmark.ips do |x|
  x.report('map.sum') { array.map(&:property).sum }
  x.report('inject(0)') { array.inject(0) { |sum, x| sum + x.property } }
  x.compare!
end

结果

Calculating -------------------------------------
             map.sum   249.000  i/100ms
           inject(0)   268.000  i/100ms
-------------------------------------------------
             map.sum      2.947k (± 5.1%) i/s -     14.691k
           inject(0)      3.089k (± 5.4%) i/s -     15.544k

Comparison:
           inject(0):     3088.9 i/s
             map.sum:     2947.5 i/s - 1.05x slower

你可以看到注射速度更快