web-dev-qa-db-fra.com

Comment additionner les propriétés des objets d'un tableau en Ruby

Je comprends que pour sommer les éléments d’un tableau en Ruby, on peut utiliser la méthode inject, c’est-à-dire.

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

Mais comment additionner les propriétés des objets dans un tableau d’objets, par exemple?

Il y a un tableau d'objets et chaque objet a une propriété "cash" par exemple. Je veux donc additionner leurs soldes de trésorerie en un seul. Quelque chose comme...

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

Je réalise que je pourrais probablement créer un nouveau tableau composé uniquement de l'argent de la propriété et le résumer, mais je recherche une méthode plus propre si possible!

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

ou

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

#reduce prend un bloc (le &:+ est un raccourci pour créer un proc/block qui fait +). C'est une façon de faire ce que vous voulez:

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

Manière la plus concise:

array.map(&:cash).sum

Si le tableau résultant de la carte ne contient aucun élément:

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

Il n'est pas nécessaire d'utiliser l'injection initiale et l'opération peut être plus courte

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

Voici quelques repères intéressants

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

Et résultats

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

Comme vous pouvez le voir, injecter un peu plus vite

1
mpospelov

Si la valeur de départ pour la somme est 0, la somme seule est identique à injecter: 

array.map(&:cash).sum

Et je préférerais la version en bloc:

array.sum { |a| a.cash }

Parce que le symbole Proc from est souvent trop limité (pas de paramètres, etc.).

(Nécessite Active_Support)

0
Christopher Oezbek