¿Cómo conseguiría encontrar un promedio de una matriz?
Si tengo la matriz:
[0,4,8,2,5,0,2,6]
El promedio me daría 3.375.
ruby-on-rails
ruby
punteado
fuente
fuente
Respuestas:
Prueba esto:
Tenga en cuenta
.to_f
lo que querrá para evitar cualquier problema de la división de enteros. También puedes hacer:Puede definirlo como parte de lo
Array
que sugirió otro comentarista, pero debe evitar la división de enteros o sus resultados serán incorrectos. Además, esto generalmente no es aplicable a todos los tipos de elementos posibles (obviamente, un promedio solo tiene sentido para cosas que se pueden promediar). Pero si quieres ir por esa ruta, usa esto:Si no lo has visto
inject
antes, no es tan mágico como podría parecer. Se itera sobre cada elemento y luego le aplica un valor acumulador. El acumulador se entrega al siguiente elemento. En este caso, nuestro acumulador es simplemente un número entero que refleja la suma de todos los elementos anteriores.Editar: El comentarista Dave Ray propuso una buena mejora.
Editar: La propuesta del comentarista Glenn Jackman, usando
arr.inject(:+).to_f
, también es buena, pero tal vez un poco demasiado inteligente si no sabes lo que está sucediendo. El:+
es un símbolo; cuando se pasa a inyectar, aplica el método nombrado por el símbolo (en este caso, la operación de suma) a cada elemento contra el valor del acumulador.fuente
arr.inject(0.0) { |sum,el| sum + el } / arr.size
.inject
interfaz, mencionada en la documentación. Elto_proc
operador es&
.Array#inject
es excesivo aquí. Solo úsalo#sum
. Por ejemploarr.sum.to_f / arr.size
Una versión de esto que no use
instance_eval
sería:fuente
instance_eval
le permite ejecutar el código mientras solo especificaa
una vez, para que pueda encadenarse con otros comandos. Es decir, enrandom_average = Array.new(10) { rand(10) }.instance_eval { reduce(:+) / size.to_f }
lugar derandom = Array.new(10) { rand(10) }; random_average = random.reduce(:+) / random.size
self
dentro de ese bloque, te encontrarás con problemas).instance_eval
Es más para metaprogramación o DSL.Creo que la respuesta más simple es
fuente
reduce
es un método deEnumerable
mezcla utilizado porArray
. Y a pesar de su nombre, estoy de acuerdo con @ShuWu ... a menos que esté usando Rails que implementasum
.Esperaba Math.average (valores), pero no tuve tanta suerte.
fuente
sum
método, por lo que parece ser una respuesta correcta después de 6 años, digna del premio Nostradamus.Las versiones de Ruby> = 2.4 tienen un método de suma # Enumerable .
Y para obtener el promedio de coma flotante, puede usar Integer # fdiv
Para versiones anteriores:
fuente
Algunos puntos de referencia de las mejores soluciones (en orden de la más eficiente):
Gran matriz:
Pequeñas matrices:
fuente
fuente
nil
lugar de 0?Permítanme traer algo a la competencia que resuelve el problema de división por cero:
Sin embargo, debo admitir que "intentar" es un ayudante de Rails. Pero puedes resolver esto fácilmente:
Por cierto: creo que es correcto que el promedio de una lista vacía sea nulo. El promedio de nada es nada, no 0. Entonces, ese es el comportamiento esperado. Sin embargo, si cambia a:
el resultado para las matrices vacías no será una excepción como esperaba, sino que devuelve NaN ... Nunca lo había visto antes en Ruby. ;-) Parece ser un comportamiento especial de la clase Float ...
fuente
lo que no me gusta de la solución aceptada
es que realmente no funciona de una manera puramente funcional. necesitamos una variable arr para calcular arr.size al final.
Para resolver esto de manera puramente funcional, necesitamos hacer un seguimiento de dos valores: la suma de todos los elementos y el número de elementos.
Santhosh mejoró esta solución: en lugar de que el argumento r sea una matriz, podríamos usar la desestructuración para separarlo inmediatamente en dos variables
si quieres ver cómo funciona, agrega algunas opciones:
También podríamos usar una estructura en lugar de una matriz para contener la suma y el recuento, pero luego tenemos que declarar la estructura primero:
fuente
end.method
en rubí, ¡gracias por esto!arr.inject([0.0,0]) { |(sum, size), el| [ sum + el, size + 1 ] }.inject(:/)
Para diversión pública, otra solución más:
fuente
No tenga Ruby en esta PC, pero algo en esta medida debería funcionar:
fuente
Añadir
Array#average
.Estaba haciendo lo mismo con bastante frecuencia, así que pensé que era prudente extender la
Array
clase con unaverage
método simple . No funciona para nada más que una matriz de números como enteros o flotantes o decimales, pero es útil cuando lo usa correctamente.Estoy usando Ruby on Rails, así que coloqué esto
config/initializers/array.rb
pero puedes colocarlo en cualquier lugar que esté incluido en el arranque, etc.config/initializers/array.rb
fuente
fuente
Resuelve dividir por cero, división entera y es fácil de leer. Se puede modificar fácilmente si elige que una matriz vacía devuelva 0.
También me gusta esta variante, pero es un poco más prolija.
fuente
fuente
Este método puede ser útil.
fuente
Sin tener que repetir la matriz (p. Ej., Perfecta para líneas simples):
fuente
Corto pero usando variable de instancia
fuente
a_size = nil; [1,2].tap { |a| a_size = a.size }.inject(:+).to_f/a_size
lugar de crear una variable de instancia.Podría intentar algo como lo siguiente:
fuente