据我所知,为了在Ruby中对数组元素求和,可以使用inject方法,即
array = [1,2,3,4,5];
puts array.inject(0, &:+)
但是如何对对象数组中对象的属性求和,例如。
有一个对象数组,每个对象都有一个属性“cash”。所以我想将他们的现金余额总计为一个。有点像...
array.cash.inject(0, &:+) # (but this doesn't work)
我意识到我可能会制作一个仅由物业现金组成的新阵列,并总结一下,但如果可能的话,我正在寻找一种更清洁的方法!
答案 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
你可以看到注射速度更快