Como obter uma média de uma matriz?
Se eu tiver a matriz:
[0,4,8,2,5,0,2,6]
A média me daria 3.375.
ruby-on-rails
ruby
dotty
fonte
fonte
Respostas:
Tente o seguinte:
Observe o
.to_f
que você deseja evitar problemas da divisão inteira. Você também pode fazer:Você pode defini-lo como parte de
Array
outro usuário sugerido, mas precisa evitar a divisão de números inteiros ou seus resultados estarão errados. Além disso, isso geralmente não é aplicável a todos os tipos de elementos possíveis (obviamente, uma média só faz sentido para coisas que podem ser calculadas em média). Mas se você quiser seguir esse caminho, use o seguinte:Se você nunca viu
inject
antes, não é tão mágico quanto parece. Ele itera sobre cada elemento e, em seguida, aplica um valor acumulador a ele. O acumulador é então entregue ao próximo elemento. Nesse caso, nosso acumulador é simplesmente um número inteiro que reflete a soma de todos os elementos anteriores.Editar: O comentarista Dave Ray propôs uma boa melhoria.
Edit: A proposta do comentarista Glenn Jackman, usando
arr.inject(:+).to_f
, também é legal, mas talvez um pouco inteligente demais, se você não sabe o que está acontecendo. O:+
é um símbolo; quando passado para injetar, aplica o método nomeado pelo símbolo (neste caso, a operação de adição) a cada elemento em relação ao valor do acumulador.fonte
arr.inject(0.0) { |sum,el| sum + el } / arr.size
.inject
interface, mencionada na documentação. Oto_proc
operador é&
.Array#inject
é um exagero aqui. Apenas use#sum
. Exemploarr.sum.to_f / arr.size
Uma versão disso que não usa
instance_eval
seria:fonte
instance_eval
permite executar o código enquanto especifica apenasa
uma vez, para que ele possa ser encadeado com outros comandos. Ou seja, emrandom_average = Array.new(10) { rand(10) }.instance_eval { reduce(:+) / size.to_f }
vez derandom = Array.new(10) { rand(10) }; random_average = random.reduce(:+) / random.size
self
dentro desse bloco, teria problemas.)instance_eval
É mais para metaprogramação ou DSL.Eu acredito que a resposta mais simples é
fonte
reduce
é um método doEnumerable
mixin usado porArray
. E, apesar do nome, concordo com o @ShuWu ... a menos que você esteja usando o Rails que implementasum
.Eu estava esperando Math.average (values), mas não tive essa sorte.
fonte
sum
método, portanto essa parece ser uma resposta correta após 6 anos, digna do prêmio Nostradamus.As versões do Ruby> = 2.4 têm um método # sum enumerável.
E para obter uma média de ponto flutuante, você pode usar o número inteiro # fdiv
Para versões mais antigas:
fonte
Alguns testes comparativos das principais soluções (na ordem das mais eficientes):
Matriz grande:
Matrizes pequenas:
fonte
fonte
nil
vez de 0?Deixe-me colocar algo em competição que resolva a divisão pelo problema zero:
Devo admitir, no entanto, que "try" é um ajudante do Rails. Mas você pode facilmente resolver isso:
BTW: Eu acho correto que a média de uma lista vazia seja nula. A média de nada é nada, não 0. Portanto, esse é o comportamento esperado. No entanto, se você mudar para:
o resultado para Arrays vazios não será uma exceção, como eu esperava, mas retorna NaN ... Eu nunca vi isso antes em Ruby. ;-) Parece ser um comportamento especial da classe Float ...
fonte
o que eu não gosto na solução aceita
é que realmente não funciona de maneira puramente funcional. precisamos de uma variável arr para calcular arr.size no final.
para resolver isso puramente funcionalmente, precisamos acompanhar dois valores: a soma de todos os elementos e o número de elementos.
Santhosh aprimorou esta solução: em vez de o argumento r ser uma matriz, poderíamos usar a desestruturação para separá-la imediatamente em duas variáveis
se você quiser ver como funciona, adicione alguns putos:
Também poderíamos usar uma estrutura em vez de uma matriz para conter a soma e a contagem, mas depois temos que declarar a estrutura primeiro:
fonte
end.method
ruby, obrigado por isso!arr.inject([0.0,0]) { |(sum, size), el| [ sum + el, size + 1 ] }.inject(:/)
Para diversão do público, mais uma solução:
fonte
Não tem ruby neste PC, mas algo nessa medida deve funcionar:
fonte
Adicionar
Array#average
.Eu fazia a mesma coisa com frequência, então achei prudente estender a
Array
classe apenas com umaverage
método simples . Ele não funciona para nada além de uma matriz de números como números inteiros ou flutuantes ou decimais, mas é útil quando você o usa corretamente.Estou usando Ruby on Rails, então coloquei isso,
config/initializers/array.rb
mas você pode colocá-lo em qualquer lugar que esteja incluído na inicialização, etc.config/initializers/array.rb
fonte
fonte
Resolve dividir por zero, divisão inteira e é fácil de ler. Pode ser facilmente modificado se você escolher que uma matriz vazia retorne 0.
Também gosto dessa variante, mas é um pouco mais prolixo.
fonte
fonte
Este método pode ser útil.
fonte
Sem ter que repetir a matriz (por exemplo, perfeita para one-liners):
fonte
Variável de instância curta, mas usando
fonte
a_size = nil; [1,2].tap { |a| a_size = a.size }.inject(:+).to_f/a_size
vez de criar uma variável de instância.Você pode tentar algo como o seguinte:
fonte