Ich verstehe, dass man, um Array-Elemente in Ruby zusammenzufassen, die Injektionsmethode verwenden kann, d. H.
array = [1,2,3,4,5];
puts array.inject(0, &:+)
Aber wie summiere ich die Eigenschaften von Objekten in einem Objekt-Array, z.
Es gibt eine Reihe von Objekten und jedes Objekt hat beispielsweise eine Eigenschaft "cash". Also möchte ich ihre Barguthaben in einer Summe zusammenfassen. So etwas wie...
array.cash.inject(0, &:+) # (but this doesn't work)
Ich erkenne, dass ich wahrscheinlich ein neues Array erstellen könnte, das nur aus der Eigenschaft cash besteht und diese zusammenfasst, aber ich suche nach einer saubereren Methode, wenn möglich!
array.map(&:cash).inject(0, &:+)
oder
array.inject(0){|sum,e| sum + e.cash }
In Ruby auf Rails könnten Sie auch versuchen:
array.sum(&:cash)
Es ist eine Abkürzung für das Inject-Geschäft und erscheint mir besser lesbar.
http://api.rubyonrails.org/classes/Enumerable.html
#reduce
nimmt einen Block (der &:+
ist eine Verknüpfung zum Erstellen einer Prozedur/eines Blocks, die +
verwendet). Dies ist eine Möglichkeit, das zu tun, was Sie möchten:
array.reduce(0) { |sum, obj| sum + obj.cash }
Der prägnanteste Weg:
array.map(&:cash).sum
Wenn das aus der Karte resultierende Array keine Elemente enthält:
array.map(&:cash).compact.sum
Es ist nicht notwendig, das Einspritzverfahren zu verwenden, und der Plusbetrieb kann kürzer sein
array.map(&:cash).inject(:+)
Hier einige interessante Benchmarks
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
Und Ergebnisse
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
Wie Sie sehen können, spritzen Sie etwas schneller
Wenn der Startwert für die Summation 0 ist, ist die Summe allein identisch mit der Einspritzung:
array.map(&:cash).sum
Und ich würde die Blockversion vorziehen:
array.sum { |a| a.cash }
Weil das Proc from-Symbol oft zu begrenzt ist (keine Parameter usw.).
(Benötigt Active_Support)