Ответ 1
array.map(&:cash).inject(0, &:+)
или
array.inject(0){|sum,e| sum + e.cash }
Я понимаю, что для суммирования элементов массива в Ruby можно использовать метод ввода, т.е.
array = [1,2,3,4,5];
puts array.inject(0, &:+)
Но как я могу суммировать свойства объектов в массиве объектов, например?
Здесь массив объектов и каждый объект имеют свойство "cash", например. Поэтому я хочу суммировать свои денежные остатки в одну общую сумму. Что-то вроде...
array.cash.inject(0, &:+) # (but this doesn't work)
Я понимаю, что, возможно, я мог бы создать новый массив, состоящий только из наличных денег и суммировать это, но я ищу более чистый метод, если это возможно!
array.map(&:cash).inject(0, &:+)
или
array.inject(0){|sum,e| sum + e.cash }
В Ruby On Rails вы также можете попробовать:
array.sum(&:cash)
Это ярлык для инъекционного бизнеса, и он кажется мне более читабельным.
http://api.rubyonrails.org/classes/Enumerable.html
#reduce
принимает блок (&:+
является ярлыком для создания proc/block, который делает +
). Это один из способов сделать то, что вы хотите:
array.reduce(0) { |sum, obj| sum + obj.cash }
Самый сжатый способ:
array.map(&:cash).sum
Если результирующий массив с карты имеет нулевые элементы:
array.map(&:cash).compact.sum
Нет необходимости использовать начальную инъекцию, а плюс операция может быть короче
array.map(&:cash).inject(:+)
Вот некоторые интересные тесты
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
Как вы можете заметить, немного ускоряется
Если начальное значение для суммирования равно 0, то сумма сама по себе идентична инъекции:
array.map(&:cash).sum
И я бы предпочел версию блока:
array.sum { |a| a.cash }
Потому что Proc из символа часто слишком ограничен (без параметров и т.д.).
(требуется Active_Support)