values - sum with index ruby




Como somar matriz de números em Ruby? (15)

Eu tenho uma matriz de 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 }

trabalharia.


Novo para o Ruby 2.4.0

Você pode usar o método apropriadamente chamado Enumerable#sum . Tem muitas vantagens sobre inject(:+) mas existem algumas notas importantes para ler no final também.

Exemplos

Gamas

(1..100).sum
#=> 5050

Matrizes

[1, 2, 4, 9, 2, 3].sum
#=> 21

[1.9, 6.3, 20.3, 49.2].sum
#=> 77.7

Nota importante

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 mais informações sobre por que a sum é assim.


É perigoso para o mokeypatch classes base e agora que o Ruby 2.4.0 tem soma em Enumerables não é necessário e perigoso. Se você gosta de perigo e usar uma versão mais antiga do Ruby, pode adicionar #sum à classe Array :

class Array
  def sum
    inject(0) { |sum, x| sum + x }
  end
end

Então faça coisas divertidas como:

[1, 2, 3, 4].sum

Como alternativa (apenas para comparação), se você tiver o Rails instalado (na verdade, apenas o ActiveSupport):

require 'activesupport'
array.sum

Este é o caminho mais curto. Tente.

array.inject :+


O Ruby 2.4.0 é lançado e tem um método Enumerable#sum . 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

Ou tente o caminho Ruby 1.9:

array.inject(0, :+)

Nota: o caso base 0 é necessário, caso contrário, nil será retornado em matrizes vazias:

> [].inject(:+)
nil
> [].inject(0, :+)
0

Ruby 1.8.7 maneira é o seguinte:

array.inject(0, &:+) 

Ruby 2.4+ / Rails - array.sum ie [1, 2, 3].sum # => 6

Ruby pre 2.4 - array.inject(:+) ou array.reduce(:+)

* Nota: O método #sum é uma nova adição ao 2.4 para enumerable assim você poderá usar o array.sum em puro rubi, não apenas no Rails.


Também 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


Você pode usar .map e .sum como:

array.map { |e| e }.sum

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

para array com valores nulos, podemos compactar e depois 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 o Array contém valores nulos e vazios, por padrão, se você usar qualquer função acima, reduza, some, injete tudo através do

TypeError: nil não pode ser coagido em Integer

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 a (s) expressão (s) Ruby (s) 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+

array.reduce(0, :+)

Embora equivalente a array.inject(0, :+) , o termo reduce está inserindo um vernáculo mais comum com o surgimento dos modelos de programação MapReduce .

injetar , reduzir , dobrar , acumular e compactar são sinônimos de uma classe de funções de dobramento . Eu acho a consistência em sua base de código mais importante, mas como várias comunidades tendem a preferir uma palavra a outra, ainda assim é útil conhecer as alternativas.

Para enfatizar o palavreado reduzir o mapa, aqui está uma versão que é um pouco mais indulgente sobre o que acaba nessa matriz.

array.map(&:to_i).reduce(0, :+)

Alguma leitura relevante adicional:





sum