sort rails objects create array ruby arrays object sum inject

rails - Cómo sumar las propiedades de los objetos dentro de una matriz en Ruby



ruby create array (7)

Aquí algunos puntos de referencia interesantes

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

Y resultados

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

Como puedes ver, inyecta un poco más rápido

Entiendo que para sumar elementos de matriz en Ruby se puede usar el método de inyección, es decir,

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

Pero, ¿cómo puedo sumar las propiedades de los objetos dentro de una matriz de objetos, por ejemplo?

Hay una variedad de objetos y cada objeto tiene una propiedad "efectivo", por ejemplo. Entonces quiero sumar sus saldos de efectivo en un total. Algo como...

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

Me doy cuenta de que probablemente podría hacer una nueva matriz compuesta solo por el efectivo de la propiedad y sumar esto, ¡pero estoy buscando un método más limpio si es posible!


La forma más concisa:

array.map(&:cash).sum

Si el conjunto resultante del mapa tiene elementos nulos:

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


No hay necesidad de usar inicial en inyección y la operación más puede ser más corta

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


Si el valor inicial para la suma es 0, entonces la suma sola es idéntica a la inyección:

array.map(&:cash).sum

Y preferiría la versión de bloque:

array.sum { |a| a.cash }

Debido a que el Proc del símbolo a menudo es demasiado limitado (sin parámetros, etc.).

(Necesita Active_Support)



#reduce toma un bloque (el &:+ es un atajo para crear un bloque / proc que hace + ). Esta es una forma de hacer lo que quieres:

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


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

o

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