metodos - ¿Cómo sumar una matriz de números en Ruby?
metodos de array en ruby (22)
Tengo una matriz de enteros.
Por ejemplo:
array = [123,321,12389]
¿Hay alguna buena manera de obtener la suma de ellos?
Yo sé eso
sum = 0
array.each { |a| sum+=a }
trabajaría.
Nuevo para Ruby 2.4.0
Puede usar el método acertadamente nombrado Enumerable#sum
. Tiene muchas ventajas sobre inject(:+)
pero también hay algunas notas importantes para leer al final.
Ejemplos
Gamas
(1..100).sum
#=> 5050
Arrays
[1, 2, 4, 9, 2, 3].sum
#=> 21
[1.9, 6.3, 20.3, 49.2].sum
#=> 77.7
Nota IMPORTANTE
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)
Vea esta respuesta para obtener más información sobre por qué la sum
es así.
Alternativamente (solo para comparación), si tiene Rails instalado (en realidad solo ActiveSupport):
require ''activesupport''
array.sum
Es peligroso para las clases base de mokeypatch y ahora que Ruby 2.4.0 tiene la suma de los Enumerables, no es necesario y es peligroso. Si te gusta el peligro y usar una versión anterior de Ruby, puedes agregar #sum
a la clase Array
:
class Array
def sum
inject(0) { |sum, x| sum + x }
end
end
Entonces haz cosas divertidas como:
[1, 2, 3, 4].sum
Este es el camino más corto. Intentalo.
array.inject :+
Esto es suficiente [1,2,3].inject(''+'')
O prueba la manera Ruby 1.9:
array.inject(0, :+)
Nota: el caso base 0
es necesario, de lo contrario se devolverá nil
en arreglos vacíos:
> [].inject(:+)
nil
> [].inject(0, :+)
0
O puedes probar este método:
def sum arr
0 if arr.empty
arr.inject :+
end
Prueba esto:
array.inject(0){|sum,x| sum + x }
Ver la Enumerable Documentación de Ruby
(nota: el caso base 0
es necesario para que 0
se devuelva en una matriz vacía en lugar de nil
)
Puedes usar .map y .sum como:
array.map { |e| e }.sum
Ruby 1.8.7 forma es la siguiente:
array.inject(0, &:+)
Ruby 2.4+ / Rails - array.sum
ie [1, 2, 3].sum # => 6
Ruby pre 2.4 - array.inject(:+)
o array.reduce(:+)
* Nota: el método #sum
es una nueva adición a 2.4 para enumerable
por lo que ahora podrá usar array.sum
en rubí puro, no solo en Rails.
Se lanza Ruby 2.4.0 y tiene un método de Enumerable#sum . Para que puedas hacer
array.sum
Ejemplos de la documentación:
{ 1 => 10, 2 => 20 }.sum {|k, v| k * v } #=> 50
(1..10).sum #=> 55
(1..10).sum {|v| v * 2 } #=> 110
Si sientes golf, puedes hacerlo.
eval([123,321,12389]*?+)
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 correcto.
Simplemente puede utilizar:
example = [1,2,3]
example.inject(:+)
Solo por 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):
array.inject(0){|sum,x| sum + x.amount}
También permite [1,2].sum{|x| x * 2 } == 6
[1,2].sum{|x| x * 2 } == 6
:
# http://madeofcode.com/posts/74-ruby-core-extension-array-sum
class Array
def 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 }
end
end
end
También podrías usar recursión.
def sum(array)
array.length == 1 ? array.pop() : array.pop() + sum(array)
end
Si no quieres ser destructivo, haz un clon.
También puedes hacerlo de manera fácil.
def sum(numbers)
return 0 if numbers.length < 1
result = 0
numbers.each { |num| result += num }
result
end
para una matriz con valores nulos podemos hacer compactos y luego inyectar la suma ex-
a = [1,2,3,4,5,12,23.45,nil,23,nil]
puts a.compact.inject(:+)
Método 1:
[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 Array contiene valores nulos y vacíos, de forma predeterminada, si utiliza alguna de las funciones anteriores, reduzca, sume, inyecte todo a través de
TypeError: nil no puede ser coaccionado en Integer
Usted puede superar esto por,
[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 la 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.reduce(0, :+)
Si bien es equivalente a array.inject(0, :+)
, el término reducir es ingresar a una lengua vernácula más común con el aumento de los modelos de programación de MapReduce .
Inyectar , reducir , plegar , acumular y comprimir son sinónimos de una clase de funciones de plegado . Considero que la coherencia en la base de su código es lo más importante, pero dado que varias comunidades tienden a preferir una palabra sobre otra, 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.
array.map(&:to_i).reduce(0, :+)
Algunas lecturas relevantes adicionales:
array.reduce(:+)
Trabaja para Ranges también ... por lo tanto,
(1..10).reduce(:+) returns 55