¿Cómo puedo usar esta forma de sumar un atributo del objeto? Mi matriz [product1, product2] Quiero sumar product1.price + product2.price. ¿Es posible usar array.inject (: +)?
Pablo Cantero
77
Puede usar un truco similar con el método de mapa: array.map (&: price) .inject (: +)
markquezada
100
array.map(&:price).inject(0, :+)Es un poco más seguro. Se asegura de que si tiene una lista vacía, obtenga 0 en lugar de cero .
johnf
11
el uso de array.map (...). inyectar (...) es ineficiente, iterará a través de todos los datos dos veces. Prueba array.inject(0) { |sum, product| sum += product.price }
Si bien es equivalente a array.inject(0, :+), el término reducir está entrando en una lengua vernácula más común con el surgimiento de los modelos de programación MapReduce .
inyectar , reducir , plegar , acumular y comprimir son sinónimos de una clase de funciones de plegado . Considero que la coherencia en su código base es lo más importante, pero dado que varias comunidades tienden a preferir una palabra sobre otra, de todos modos es útil conocer las alternativas.
Para enfatizar el lenguaje de reducción de mapas, aquí hay una versión que es un poco más indulgente con lo que termina en esa matriz.
Estoy de acuerdo, reduceme dice más de lo que hace la función, pero injectsuena mucho mejor.
everett1992
1
De acuerdo con el último comentario, me diste la mejor respuesta.
Jerska
1
El único comentario que haría es eso reducey mapcomo funciones de orden superior son anteriores a MapReduce. La inspiración va para otro lado. Y en el sentido de MapReduce, es una operación algo diferente a una simple reducción funcional, que tiene implicaciones sobre cómo se comunican las diferentes máquinas.
acjay
Ken Iverson introdujo el operador / llamado "operador de reducción" en el lenguaje de programación APL. Fuente: Iverson, Kenneth. 1962. Un lenguaje de programación. Wiley Otra fuente: "Notación como herramienta de pensamiento", Conferencia del Premio ACM Turing 1979, Kenneth E. Iverson, dl.acm.org/ft_gateway.cfm?id=1283935&type=pdf
Fernando Pelliccioni
112
Alternativamente (solo para comparación), si tiene Rails instalado (en realidad solo ActiveSupport):
Las versiones más recientes de activeiveupport en realidad no cargan todas las extensiones de forma predeterminada. Usted querrá tampoco requieren sólo la suma módulo: require 'active_support/core_ext/enumerable.rb', o exigir a las de apoyo activo: require 'active_support/all'. Más sobre esto aquí: API Docs
dcashman
2
No importa que activesupportsea una dependencia masiva para arrastrar a un proyecto para ir array.inject(:+)a array.sum.
Meagar
1
Nitpick a un comentario bueno: debería estar require 'active_support/core_ext/enumerable'sin el .rbsufijo, ya que se agrega implícitamente.
Según Lundberg el
72
Para Ruby> = 2.4.0 puede usar sumde Enumerables.
[1,2,3,4].sum
Es peligroso para las clases base mokeypatch. Si le gusta el peligro y utiliza una versión anterior de Ruby, puede agregar #suma la Arrayclase:
classArraydef sum
inject(0){|sum, x| sum + x }endend
El punto que está diciendo es que no necesita hacer el parche de mono para Ruby> = 2.4, y que el parche de mono es peligroso, y que ahora puede sumar enumerables de forma nativa, pero también hay una manera de respaldar la funcionalidad.
Peter H. Boling
Voto negativo porque su implementación devuelve nulo en matrices vacías.
Eldritch Conundrum
45
Nuevo para Ruby 2.4.0
Puede usar el método acertadamente nombrado Enumerable#sum. Tiene muchas ventajas, inject(:+)pero también hay algunas notas importantes para leer al final.
Este método no es equivalente a #inject(:+). Por ejemplo
%w(a b c).inject(:+)#=> "abc"%w(a b c).sum
#=> TypeError: String can't be coerced into Integer
También,
(1..1000000000).sum
#=> 500000000500000000 (execution time: less than 1s)(1..1000000000).inject(:+)#=> 500000000500000000 (execution time: upwards of a minute)
Consulte esta respuesta para obtener más información sobre por qué sumes así.
Ruby 2.4.0 fue lanzado hoy con esta característica incluida. Amo
amoebe
@amoebe tienes razón! Me alegra ver esta característica útil incluida.
recoge el
19
Solo por el bien de la diversidad, también puede hacer esto si su matriz no es una matriz de números, sino una matriz de objetos que tienen propiedades que son números (por ejemplo, cantidad):
Esto es equivalente a hacer: array.map(&:amount).inject(0, :+). Ver otras respuestas.
Richard Jones
44
En cierto modo, sí. Sin embargo, utilizando mapa continuación injectrequiere que recorrer la matriz dos veces: una vez para crear una nueva matriz, el otro para resumir los miembros. Este método es un poco más detallado, pero también más eficiente.
# http://madeofcode.com/posts/74-ruby-core-extension-array-sumclassArraydef sum(method =nil,&block)if block_given?
raise ArgumentError,"You cannot pass a block and a method!"if method
inject(0){|sum, i| sum +yield(i)}elsif method
inject(0){|sum, i| sum + i.send(method)}else
inject(0){|sum, i| sum + i }endendend
Esto creará una cadena "123 + 321 + 12389" y luego usará la función eval para hacer la suma. Esto es solo para fines de golf , no debe usarlo en el código adecuado.
[1] pry(main)>[1,2,3,4].sum
=>10[2] pry(main)>[].sum
=>0[3] pry(main)>[1,2,3,5,nil].sum
TypeError:nil can't be coerced into Integer
Método 2:
[24] pry(main)>[].inject(:+)=>nil[25] pry(main)>[].inject(0,:+)=>0[4] pry(main)>[1,2,3,4,5].inject(0,:+)=>15[5] pry(main)>[1,2,3,4,nil].inject(0,:+)TypeError:nil can't be coerced into Integer
from (pry):5:in `+'
Método 3:
[6] pry(main)>[1,2,3].reduce(:+)=>6[9] pry(main)>[].reduce(:+)=>nil[7] pry(main)>[1,2,nil].reduce(:+)TypeError:nil can't be coerced into Integer
from (pry):7:in `+'
Método 4:
cuando la matriz contiene valores nulos y vacíos, de manera predeterminada si utiliza alguna de las funciones anteriores, reduzca, sume, inyecte todo a través del
TypeError: nil no se puede convertir en Integer
Puedes superar esto,
[16] pry(main)> sum =0=>0[17] pry(main)>[1,2,3,4,nil,''].each{|a| sum+= a.to_i }=>[1,2,3,4,nil,""][18] pry(main)> sum
=>10
Método 6: eval
Evalúa las expresiones de Ruby en cadena.
[26] pry(main)> a =[1,3,4,5]=>[1,3,4,5][27] pry(main)> eval a.join '+'=>13[30] pry(main)> a =[1,3,4,5,nil]=>[1,3,4,5,nil][31] pry(main)> eval a.join '+'SyntaxError:(eval):1: syntax error, unexpected end-of-input
1+3+4+5+
array.sum
Respuestas:
Prueba esto:
Ver la documentación enumerable de Ruby
(nota: el
0
caso base es necesario para que0
se devuelva en una matriz vacía en lugar denil
)fuente
array.inject(:+)
es más eficiente.array.inject(:+)
parece causar problemas en Ruby 1.8.6. Pueden aparecer excepciones "LocalJumpError: sin bloque".array.sum
puede darte la suma de los valores de la matriz.reduce
, que es un alias deinject
(como enarray.reduce( :+ )
).inject
lugar dereduce
.O prueba la forma Ruby 1.9:
Nota: el
0
caso base es necesario; de lo contrarionil
, se devolverá en matrices vacías:fuente
array.map(&:price).inject(0, :+)
Es un poco más seguro. Se asegura de que si tiene una lista vacía, obtenga 0 en lugar de cero .array.inject(0) { |sum, product| sum += product.price }
Si bien es equivalente a
array.inject(0, :+)
, el término reducir está entrando en una lengua vernácula más común con el surgimiento de los modelos de programación MapReduce .inyectar , reducir , plegar , acumular y comprimir son sinónimos de una clase de funciones de plegado . Considero que la coherencia en su código base es lo más importante, pero dado que varias comunidades tienden a preferir una palabra sobre otra, de todos modos es útil conocer las alternativas.
Para enfatizar el lenguaje de reducción de mapas, aquí hay una versión que es un poco más indulgente con lo que termina en esa matriz.
Algunas lecturas relevantes adicionales:
fuente
reduce
me dice más de lo que hace la función, peroinject
suena mucho mejor.reduce
ymap
como funciones de orden superior son anteriores a MapReduce. La inspiración va para otro lado. Y en el sentido de MapReduce, es una operación algo diferente a una simple reducción funcional, que tiene implicaciones sobre cómo se comunican las diferentes máquinas.Alternativamente (solo para comparación), si tiene Rails instalado (en realidad solo ActiveSupport):
fuente
require 'active_support/core_ext/enumerable.rb'
, o exigir a las de apoyo activo:require 'active_support/all'
. Más sobre esto aquí: API Docsactivesupport
sea una dependencia masiva para arrastrar a un proyecto para irarray.inject(:+)
aarray.sum
.require 'active_support/core_ext/enumerable'
sin el.rb
sufijo, ya que se agrega implícitamente.Para Ruby> = 2.4.0 puede usar
sum
de Enumerables.Es peligroso para las clases base mokeypatch. Si le gusta el peligro y utiliza una versión anterior de Ruby, puede agregar
#sum
a laArray
clase:fuente
Nuevo para Ruby 2.4.0
Puede usar el método acertadamente nombrado
Enumerable#sum
. Tiene muchas ventajas,inject(:+)
pero también hay algunas notas importantes para leer al final.Ejemplos
Rangos
Matrices
Nota IMPORTANTE
Este método no es equivalente a
#inject(:+)
. Por ejemploTambién,
Consulte esta respuesta para obtener más información sobre por qué
sum
es así.fuente
Ruby 2.4+ / Rails -
array.sum
es decir[1, 2, 3].sum # => 6
Ruby pre 2.4 -
array.inject(:+)
oarray.reduce(:+)
* Nota: El
#sum
método es una nueva adición a 2.4, porenumerable
lo que ahora podrá usarloarray.sum
en rubí puro, no solo en Rails.fuente
Solo por el bien de la diversidad, también puede hacer esto si su matriz no es una matriz de números, sino una matriz de objetos que tienen propiedades que son números (por ejemplo, cantidad):
fuente
array.map(&:amount).inject(0, :+)
. Ver otras respuestas.map
a continuacióninject
requiere que recorrer la matriz dos veces: una vez para crear una nueva matriz, el otro para resumir los miembros. Este método es un poco más detallado, pero también más eficiente.ruby 1.8.7 way es el siguiente:
fuente
Simplemente puede usar:
fuente
inject(:+)
pero esto noinject :+
?Esto es suficiente
[1,2,3].inject('+')
fuente
Se lanza Ruby 2.4.0 y tiene un método Enumerable # sum . Entonces puedes hacer
Ejemplos de los documentos:
fuente
También permite
[1,2].sum{|x| x * 2 } == 6
:fuente
para una matriz con valores nulos podemos hacer compactos y luego inyectar la suma ex
fuente
Funciona también para rangos ... por lo tanto,
fuente
Si te sientes golfista, puedes hacer
Esto creará una cadena "123 + 321 + 12389" y luego usará la función eval para hacer la suma. Esto es solo para fines de golf , no debe usarlo en el código adecuado.
fuente
Método 1:
Método 2:
Método 3:
Método 4: cuando la matriz contiene valores nulos y vacíos, de manera predeterminada si utiliza alguna de las funciones anteriores, reduzca, sume, inyecte todo a través del
Puedes superar esto,
Método 6: eval
Evalúa las expresiones de Ruby en cadena.
fuente
3 formas en que podemos hacer la suma de la matriz
1)
array.inject(0){|sum,x| sum + x }
2)
array.inject('+')
3)
array.join('+')
fuente
O puedes probar este método:
fuente
Este es el camino más corto. Intentalo.
array.inject :+
fuente
* Esto funcionó bien para mí como nuevo desarrollador. Puede ajustar su rango de números cambiando los valores dentro de []
fuente
También puedes hacerlo de manera fácil
fuente
Puede usar .map y .sum como:
fuente
array.sum