web-dev-qa-db-de.com

Wie werden Eigenschaften von Objekten innerhalb eines Arrays in Ruby zusammengefasst?

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!

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

oder

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

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

49
jacklin

#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 }
9
Theo

Der prägnanteste Weg:

array.map(&:cash).sum

Wenn das aus der Karte resultierende Array keine Elemente enthält:

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

Es ist nicht notwendig, das Einspritzverfahren zu verwenden, und der Plusbetrieb kann kürzer sein

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

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

1
mpospelov

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)

0