Comment trouver une moyenne à partir d'un tableau?
Si j'ai le tableau:
[0,4,8,2,5,0,2,6]
La moyenne me donnerait 3,375.
ruby-on-rails
ruby
dingue
la source
la source
Réponses:
Essaye ça:
Notez le
.to_f
, que vous voudrez pour éviter tout problème de division entière. Vous pouvez également faire:Vous pouvez le définir comme faisant partie d'
Array
un autre commentateur l'a suggéré, mais vous devez éviter la division entière ou vos résultats seront erronés. En outre, cela n'est généralement pas applicable à tous les types d'éléments possibles (évidemment, une moyenne n'a de sens que pour les choses qui peuvent être moyennées). Mais si vous voulez suivre cette voie, utilisez ceci:Si vous ne l'avez pas vu
inject
auparavant, ce n'est pas aussi magique qu'il y paraît. Il itère sur chaque élément et lui applique ensuite une valeur d'accumulateur. L'accumulateur est ensuite remis à l'élément suivant. Dans ce cas, notre accumulateur est simplement un entier qui reflète la somme de tous les éléments précédents.Edit: le commentateur Dave Ray a proposé une belle amélioration.
Edit: La proposition du commentateur Glenn Jackman, en utilisant
arr.inject(:+).to_f
, est bien aussi mais peut-être un peu trop intelligente si vous ne savez pas ce qui se passe. Le:+
est un symbole; lorsqu'il est passé à l'injection, il applique la méthode nommée par le symbole (dans ce cas, l'opération d'addition) à chaque élément par rapport à la valeur de l'accumulateur.la source
arr.inject(0.0) { |sum,el| sum + el } / arr.size
.inject
interface, mentionnée dans la documentation. L'to_proc
opérateur est&
.Array#inject
c'est exagéré ici. Utilisez simplement#sum
. Par exemplearr.sum.to_f / arr.size
Une version de ceci qui n'utilise pas
instance_eval
serait:la source
instance_eval
vous permet d'exécuter le code en ne spécifianta
qu'une seule fois, afin qu'il puisse être enchaîné avec d'autres commandes. C'est-à-direrandom_average = Array.new(10) { rand(10) }.instance_eval { reduce(:+) / size.to_f }
au lieu derandom = Array.new(10) { rand(10) }; random_average = random.reduce(:+) / random.size
self
intérieur de ce bloc, vous rencontrez des problèmes.)instance_eval
Est plus pour la métaprogrammation ou DSL.Je crois que la réponse la plus simple est
la source
reduce
est une méthode deEnumerable
mixage utilisée parArray
. Et malgré son nom, je suis d'accord avec le @ShuWu ... sauf si vous utilisez Rails qui implémentesum
.J'espérais pour Math.average (valeurs), mais pas de chance.
la source
sum
méthode, donc cela semble être une réponse correcte après 6 ans, digne du prix Nostradamus.Les versions Ruby> = 2.4 ont une méthode de somme Enumerable # .
Et pour obtenir une moyenne à virgule flottante, vous pouvez utiliser Integer # fdiv
Pour les anciennes versions:
la source
Quelques analyses comparatives des meilleures solutions (dans l'ordre des plus efficaces):
Grand tableau:
Petits tableaux:
la source
la source
nil
plutôt que 0?Permettez-moi de mettre quelque chose en compétition qui résout le problème de la division par zéro:
Je dois admettre, cependant, que «essayer» est un assistant Rails. Mais vous pouvez facilement résoudre ce problème:
BTW: Je pense qu'il est exact que la moyenne d'une liste vide est nulle. La moyenne de rien n'est rien, pas 0. C'est donc le comportement attendu. Cependant, si vous passez à:
le résultat pour les tableaux vides ne sera pas une exception comme je m'y attendais, mais à la place, il renvoie NaN ... Je n'ai jamais vu cela auparavant dans Ruby. ;-) Semble être un comportement spécial de la classe Float ...
la source
ce que je n'aime pas dans la solution acceptée
c'est qu'il ne fonctionne pas vraiment de manière purement fonctionnelle. nous avons besoin d'une variable arr pour calculer arr.size à la fin.
pour résoudre ce problème de manière purement fonctionnelle, nous devons garder une trace de deux valeurs: la somme de tous les éléments et le nombre d'éléments.
Santhosh a amélioré cette solution: au lieu que l'argument r soit un tableau, nous pourrions utiliser la déstructuration pour le séparer immédiatement en deux variables
si vous voulez voir comment ça marche, ajoutez quelques put:
Nous pourrions également utiliser une structure au lieu d'un tableau pour contenir la somme et le nombre, mais nous devons ensuite déclarer la structure en premier:
la source
end.method
utilisée en rubis, merci pour ça!arr.inject([0.0,0]) { |(sum, size), el| [ sum + el, size + 1 ] }.inject(:/)
Pour le plaisir du public, encore une autre solution:
la source
Ne pas avoir de rubis sur ce PC, mais quelque chose dans cette mesure devrait fonctionner:
la source
Ajouter
Array#average
.Je faisais la même chose assez souvent, donc j'ai pensé qu'il était prudent de simplement étendre la
Array
classe avec uneaverage
méthode simple . Cela ne fonctionne pas pour autre chose qu'un tableau de nombres comme des entiers ou des flottants ou des décimales, mais c'est pratique lorsque vous l'utilisez correctement.J'utilise Ruby on Rails, donc je l'ai placé
config/initializers/array.rb
mais vous pouvez le placer n'importe où qui est inclus au démarrage, etc.config/initializers/array.rb
la source
la source
Résout la division par zéro, division entière et est facile à lire. Peut être facilement modifié si vous choisissez qu'un tableau vide renvoie 0.
J'aime aussi cette variante, mais elle est un peu plus verbeuse.
la source
la source
Cette méthode peut être utile.
la source
Sans avoir à répéter le tableau (par exemple parfait pour les lignes simples):
la source
Courte mais utilisant une variable d'instance
la source
a_size = nil; [1,2].tap { |a| a_size = a.size }.inject(:+).to_f/a_size
plutôt que de créer une variable d'instance.Vous pouvez essayer quelque chose comme ceci:
la source