Eu tenho uma matriz de números inteiros.
Por exemplo:
array = [123,321,12389]
Existe alguma maneira legal de obter a soma deles?
Eu sei disso
sum = 0
array.each { |a| sum+=a }
podia funcionar.
Eu tenho uma matriz de números inteiros.
Por exemplo:
array = [123,321,12389]
Existe alguma maneira legal de obter a soma deles?
Eu sei disso
sum = 0
array.each { |a| sum+=a }
podia funcionar.
Respostas:
Tente o seguinte:
array.inject(0){|sum,x| sum + x }
Veja a documentação numerável do Ruby
(nota: o 0
caso base é necessário para que 0
seja retornado em uma matriz vazia em vez de nil
)
array.inject(:+)
é mais eficiente.
array.inject(:+)
parece causar problemas no Ruby 1.8.6 Exceções "LocalJumpError: nenhum bloco fornecido" podem aparecer.
array.sum
você pode somar os valores do array.
reduce
, que é um apelido de inject
(como em array.reduce( :+ )
).
inject
e não reduce
.
Ou tente o Ruby 1.9:
array.inject(0, :+)
Nota: o 0
caso base é necessário, caso contrário nil
, será retornado em matrizes vazias:
> [].inject(:+)
nil
> [].inject(0, :+)
0
array.map(&:price).inject(0, :+)
é um pouco mais seguro. Ele garante que, se você tiver uma lista vazia, obtenha 0 em vez de nulo .
array.inject(0) { |sum, product| sum += product.price }
array.reduce(0, :+)
Embora equivalente array.inject(0, :+)
, o termo reduzir está entrando em um vernáculo mais comum com o aumento dos modelos de programação do MapReduce .
injetar , reduzir , dobrar , acumular e compactar são sinônimos como uma classe de funções de dobragem . Considero a consistência na sua base de códigos mais importante, mas como várias comunidades preferem uma palavra a outra, é útil conhecer as alternativas.
Para enfatizar o palavreado de redução de mapa, aqui está uma versão que perdoa um pouco o que acaba nessa matriz.
array.map(&:to_i).reduce(0, :+)
Algumas leituras relevantes adicionais:
reduce
me diz mais sobre o que a função faz, mas inject
soa muito mais legal.
reduce
e map
como as funções de ordem superior são anteriores ao MapReduce. A inspiração segue o contrário. E no sentido do MapReduce, é uma operação um pouco diferente de uma simples redução funcional, com implicações na forma como diferentes máquinas se comunicam.
Como alternativa (apenas para comparação), se você tiver o Rails instalado (na verdade, apenas o ActiveSupport):
require 'activesupport'
array.sum
require 'active_support/core_ext/enumerable.rb'
ou exigir de todos o apoio ativo: require 'active_support/all'
. Mais sobre isso aqui: API Docs
activesupport
é uma enorme dependência para arrastar em um projeto para ir de array.inject(:+)
para array.sum
.
require 'active_support/core_ext/enumerable'
sem o .rb
sufixo, já que foi adicionado implicitamente.
Para Ruby> = 2.4.0, você pode usar a sum
partir de Enumerables.
[1, 2, 3, 4].sum
É perigoso mokeypatch classes base. Se você gosta de perigo e usa uma versão mais antiga do Ruby, pode adicionar #sum
à Array
classe:
class Array
def sum
inject(0) { |sum, x| sum + x }
end
end
Você pode usar o método com nome apropriado Enumerable#sum
. Tem muitas vantagens, inject(:+)
mas existem algumas notas importantes para ler no final.
(1..100).sum
#=> 5050
[1, 2, 4, 9, 2, 3].sum
#=> 21
[1.9, 6.3, 20.3, 49.2].sum
#=> 77.7
Este método não é equivalente a #inject(:+)
. Por exemplo
%w(a b c).inject(:+)
#=> "abc"
%w(a b c).sum
#=> TypeError: String can't be coerced into Integer
Além disso,
(1..1000000000).sum
#=> 500000000500000000 (execution time: less than 1s)
(1..1000000000).inject(:+)
#=> 500000000500000000 (execution time: upwards of a minute)
Veja esta resposta para obter mais informações sobre o motivo sum
.
Ruby 2.4+ / Rails - array.sum
ie[1, 2, 3].sum # => 6
Ruby pré 2.4 - array.inject(:+)
ouarray.reduce(:+)
* Nota: O #sum
método é uma nova adição à 2.4 para enumerable
que agora você poderá usar array.sum
o Ruby puro, não apenas o Rails.
Apenas por uma questão de diversidade, você também pode fazer isso se sua matriz não for uma matriz de números, mas sim uma matriz de objetos que possuam propriedades que são números (por exemplo, quantidade):
array.inject(0){|sum,x| sum + x.amount}
array.map(&:amount).inject(0, :+)
. Veja outras respostas.
map
então inject
exige que você faça um loop pela matriz duas vezes: uma vez para criar uma nova matriz, a outra para somar os membros. Este método é um pouco mais detalhado, mas também mais eficiente.
ruby 1.8.7 way é o seguinte:
array.inject(0, &:+)
Você pode simplesmente usar:
example = [1,2,3]
example.inject(:+)
inject(:+)
mas isso não funciona inject :+
?
Isto é suficiente
[1,2,3].inject('+')
O Ruby 2.4.0 é lançado e possui um método # sum Enumerable . Então você pode fazer
array.sum
Exemplos dos documentos:
{ 1 => 10, 2 => 20 }.sum {|k, v| k * v } #=> 50
(1..10).sum #=> 55
(1..10).sum {|v| v * 2 } #=> 110
Também permite [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
para um array com valores nulos, podemos compactar e injetar a soma
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: Quando a Matriz contém valores nulos e vazios, por padrão, se você usar alguma das funções acima, reduza, some, injete tudo o que for necessário através do método
TypeError: nil não pode ser coagido em Inteiro
Você pode superar isso,
[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
Avalia as expressões Ruby na string.
[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+
Este é o caminho mais curto. Tente.
array.inject :+
number = [1..100]
number. each do |n|
final_number = n.sum
puts "The sum is #{final_number}"
end
* Isso funcionou bem para mim como um novo desenvolvedor. Você pode ajustar seu intervalo de números alterando os valores dentro de []
Você também pode fazer isso de maneira fácil
def sum(numbers)
return 0 if numbers.length < 1
result = 0
numbers.each { |num| result += num }
result
end
Você pode usar .map e .sum como:
array.map { |e| e }.sum
array.sum
array.sum