Como posso usar dessa maneira para somar um atributo do objeto. Minha matriz [product1, product2] Quero somar product1.price + product2.price. É possível usar array.inject (: +)?
21411 Pablo Cantero
7
Você pode usar um truque semelhante com o método do mapa: array.map (&: preço) .inject (: +)
markquezada
100
array.map(&:price).inject(0, :+)é um pouco mais seguro. Ele garante que, se você tiver uma lista vazia, obtenha 0 em vez de nulo .
johnf
11
usando array.map (...). inject (...) é ineficiente, você repetirá todos os dados duas vezes. Tente array.inject(0) { |sum, product| sum += product.price }
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.
Eu concordo, reduceme diz mais sobre o que a função faz, mas injectsoa muito mais legal.
everett1992
1
Concordo com o último comentário, você me deu a melhor resposta.
Jerska
1
O único comentário que eu faria é que, reducee mapcomo 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.
acjay
Ken Iverson introduziu o operador / chamado "operador de redução" na linguagem de programação APL. Fonte: Iverson, Kenneth. 1962. Uma linguagem de programação. Wiley. Outra fonte: "Notação como uma ferramenta de pensamento" de 1979 ACM Turing Award Lecture, Kenneth E. Iverson, dl.acm.org/ft_gateway.cfm?id=1283935&type=pdf
Fernando Pelliccioni
112
Como alternativa (apenas para comparação), se você tiver o Rails instalado (na verdade, apenas o ActiveSupport):
Versões mais recentes do activesupport não carregam todas as extensões por padrão. Você vai querer ou exigirá apenas o módulo de soma: require 'active_support/core_ext/enumerable.rb'ou exigir de todos o apoio ativo: require 'active_support/all'. Mais sobre isso aqui: API Docs
dcashman 21/03
2
Não importa que activesupporté uma enorme dependência para arrastar em um projeto para ir de array.inject(:+)para array.sum.
meagar
1
Nitpick para um comentário bom: caso contrário, ele deve ser require 'active_support/core_ext/enumerable'sem o .rbsufixo, já que foi adicionado implicitamente.
Por Lundberg
72
Para Ruby> = 2.4.0, você pode usar a sumpartir 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à Arrayclasse:
classArraydef sum
inject(0){|sum, x| sum + x }endend
O argumento que ele está argumentando é que você não precisa fazer o Patch do Macaco para Ruby> = 2.4, e que o patch do macaco é perigoso, e que agora você pode somar enumeráveis nativamente, mas também há uma maneira de suportar a funcionalidade.
precisa saber é o seguinte
Voto negativo porque sua implementação retorna nulo em matrizes vazias.
Eldritch Conundrum
45
Novo no Ruby 2.4.0
Você pode usar o método com nome apropriado Enumerable#sum. Tem muitas vantagens, inject(:+)mas existem algumas notas importantes para ler no final.
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.
O Ruby 2.4.0 foi lançado hoje com esse recurso incluído! 🎉
amoebe
@amoebe você está correto! Fico feliz em ver esse recurso útil incluído.
colete
19
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):
Isto é equivalente a fazer: array.map(&:amount).inject(0, :+). Veja outras respostas.
Richard Jones
4
De certa forma, sim. No entanto, o uso mapentão injectexige 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.
# 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
Isso criará uma sequência "123 + 321 + 12389" e, em seguida, usará a função eval para fazer a soma. Isso é apenas para fins de golfe , você não deve usá-lo no código apropriado.
[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+
array.sum
Respostas:
Tente o seguinte:
Veja a documentação numerável do Ruby
(nota: o
0
caso base é necessário para que0
seja retornado em uma matriz vazia em vez denil
)fonte
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 deinject
(como emarray.reduce( :+ )
).inject
e nãoreduce
.Ou tente o Ruby 1.9:
Nota: o
0
caso base é necessário, caso contrárionil
, será retornado em matrizes vazias:fonte
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 }
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.
Algumas leituras relevantes adicionais:
fonte
reduce
me diz mais sobre o que a função faz, masinject
soa muito mais legal.reduce
emap
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):
fonte
require 'active_support/core_ext/enumerable.rb'
ou exigir de todos o apoio ativo:require 'active_support/all'
. Mais sobre isso aqui: API Docsactivesupport
é uma enorme dependência para arrastar em um projeto para ir dearray.inject(:+)
paraarray.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.É perigoso mokeypatch classes base. Se você gosta de perigo e usa uma versão mais antiga do Ruby, pode adicionar
#sum
àArray
classe:fonte
Novo no Ruby 2.4.0
Você pode usar o método com nome apropriado
Enumerable#sum
. Tem muitas vantagens,inject(:+)
mas existem algumas notas importantes para ler no final.Exemplos
Gamas
Matrizes
Nota importante
Este método não é equivalente a
#inject(:+)
. Por exemploAlém disso,
Veja esta resposta para obter mais informações sobre o motivo
sum
.fonte
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 paraenumerable
que agora você poderá usararray.sum
o Ruby puro, não apenas o Rails.fonte
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):
fonte
array.map(&:amount).inject(0, :+)
. Veja outras respostas.map
entãoinject
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:
fonte
Você pode simplesmente usar:
fonte
inject(:+)
mas isso não funcionainject :+
?Isto é suficiente
[1,2,3].inject('+')
fonte
O Ruby 2.4.0 é lançado e possui um método # sum Enumerable . Então você pode fazer
Exemplos dos documentos:
fonte
Também permite
[1,2].sum{|x| x * 2 } == 6
:fonte
para um array com valores nulos, podemos compactar e injetar a soma
fonte
Também funciona para intervalos ... portanto,
fonte
Se você sente golfe, pode fazer
Isso criará uma sequência "123 + 321 + 12389" e, em seguida, usará a função eval para fazer a soma. Isso é apenas para fins de golfe , você não deve usá-lo no código apropriado.
fonte
Método 1:
Método 2:
Método 3:
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
Você pode superar isso,
Método 6: eval
Avalia as expressões Ruby na string.
fonte
3 maneiras que podemos fazer soma de matriz
1)
array.inject(0){|sum,x| sum + x }
2)
array.inject('+')
3)
array.join('+')
fonte
Ou você pode tentar este método:
fonte
Este é o caminho mais curto. Tente.
array.inject :+
fonte
* Isso funcionou bem para mim como um novo desenvolvedor. Você pode ajustar seu intervalo de números alterando os valores dentro de []
fonte
Você também pode fazer isso de maneira fácil
fonte
Você pode usar .map e .sum como:
fonte
array.sum