Wie würde man einen Durchschnitt aus einem Array finden?
Wenn ich das Array habe:
[0,4,8,2,5,0,2,6]
Die Mittelung würde mir 3,375 geben.
ruby-on-rails
ruby
dotty
quelle
quelle
Antworten:
Versuche dies:
Beachten Sie die
.to_f
, die Sie benötigen, um Probleme durch die Ganzzahldivision zu vermeiden. Sie können auch tun:Sie können es als Teil von definieren, wie es ein
Array
anderer Kommentator vorgeschlagen hat, aber Sie müssen die Ganzzahldivision vermeiden, da sonst Ihre Ergebnisse falsch sind. Dies gilt auch nicht generell für jeden möglichen Elementtyp (offensichtlich macht ein Durchschnitt nur für Dinge Sinn, die gemittelt werden können). Wenn Sie diesen Weg gehen möchten, verwenden Sie Folgendes:Wenn Sie noch nie gesehen
inject
haben, ist es nicht so magisch, wie es scheinen mag. Es iteriert über jedes Element und wendet dann einen Akkumulatorwert darauf an. Der Akku wird dann an das nächste Element übergeben. In diesem Fall ist unser Akkumulator einfach eine Ganzzahl, die die Summe aller vorherigen Elemente widerspiegelt.Edit: Kommentator Dave Ray schlug eine nette Verbesserung vor.
Bearbeiten: Der Vorschlag von Kommentator Glenn Jackman
arr.inject(:+).to_f
ist auch nett, aber vielleicht ein bisschen zu klug, wenn Sie nicht wissen, was los ist. Das:+
ist ein Symbol; Wenn es zum Injizieren übergeben wird, wendet es die durch das Symbol benannte Methode (in diesem Fall die Additionsoperation) auf jedes Element gegen den Akkumulatorwert an.quelle
arr.inject(0.0) { |sum,el| sum + el } / arr.size
.inject
Schnittstelle, die in der Dokumentation erwähnt wird. Derto_proc
Betreiber ist&
.Array#inject
ist dies hier übertrieben. Einfach benutzen#sum
. ZBarr.sum.to_f / arr.size
Eine Version davon, die nicht verwendet wird,
instance_eval
wäre:quelle
instance_eval
Mit dieser Option können Sie den Code ausführen, während Sie ihn nura
einmal angeben , damit er mit anderen Befehlen verkettet werden kann. Dhrandom_average = Array.new(10) { rand(10) }.instance_eval { reduce(:+) / size.to_f }
stattrandom = Array.new(10) { rand(10) }; random_average = random.reduce(:+) / random.size
self
in diesem Block zuzugreifen , treten Probleme auf.)instance_eval
Dies gilt eher für Metaprogrammierung oder DSL.Ich glaube, die einfachste Antwort ist
quelle
reduce
ist eine Methode desEnumerable
Mixins vonArray
. Und trotz seines Namens stimme ich dem @ShuWu zu ... es sei denn, Sie verwenden Rails, die implementiert werdensum
.Ich hatte auf Math.average (Werte) gehofft, aber kein solches Glück.
quelle
sum
Methode, so ist dies eine richtige Antwort nach 6 Jahren zu sein scheint, würdig der Nostradamus Auszeichnung.Ruby-Versionen> = 2.4 haben eine Aufzählbare # Summe Methode.
Und um den Gleitkomma-Durchschnitt zu erhalten, können Sie Integer # fdiv verwenden
Für ältere Versionen:
quelle
Einige Benchmarking von Top-Lösungen (in der Reihenfolge der effizientesten):
Großes Array:
Kleine Arrays:
quelle
quelle
nil
0 haben?Lassen Sie mich etwas in den Wettbewerb bringen, das das Problem der Division durch Null löst:
Ich muss jedoch zugeben, dass "try" ein Rails-Helfer ist. Aber Sie können dies leicht lösen:
Übrigens: Ich denke, es ist richtig, dass der Durchschnitt einer leeren Liste Null ist. Der Durchschnitt von nichts ist nichts, nicht 0. Das ist also erwartetes Verhalten. Wenn Sie jedoch zu Folgendem wechseln:
Das Ergebnis für leere Arrays ist keine Ausnahme, wie ich erwartet hatte, sondern gibt NaN zurück ... Das habe ich in Ruby noch nie gesehen. ;-) Scheint ein besonderes Verhalten der Float-Klasse zu sein ...
quelle
Was ich an der akzeptierten Lösung nicht mag
ist, dass es nicht wirklich rein funktional funktioniert. Wir brauchen eine Variable arr, um arr.size am Ende zu berechnen.
Um dies rein funktional zu lösen, müssen wir zwei Werte verfolgen: die Summe aller Elemente und die Anzahl der Elemente.
Santhosh hat diese Lösung verbessert: Anstatt das Argument r als Array zu verwenden, könnten wir die Destrukturierung verwenden, um es sofort in zwei Variablen zu zerlegen
Wenn Sie sehen möchten, wie es funktioniert, fügen Sie einige Puts hinzu:
Wir könnten auch eine Struktur anstelle eines Arrays verwenden, um die Summe und die Anzahl zu enthalten, aber dann müssen wir zuerst die Struktur deklarieren:
quelle
end.method
in Rubin verwendet sehe , danke dafür!arr.inject([0.0,0]) { |(sum, size), el| [ sum + el, size + 1 ] }.inject(:/)
Zur öffentlichen Unterhaltung noch eine andere Lösung:
quelle
Haben Sie keinen Rubin auf diesem PC, aber etwas in diesem Ausmaß sollte funktionieren:
quelle
Hinzufügen
Array#average
.Ich habe ziemlich oft das Gleiche gemacht, deshalb fand ich es klug, die
Array
Klasse nur mit einem einfachen zu erweiternaverage
Methode zu erweitern. Es funktioniert nur für ein Array von Zahlen wie Integer oder Floats oder Decimals, aber es ist praktisch, wenn Sie es richtig verwenden.Ich verwende Ruby on Rails, also habe ich dies platziert,
config/initializers/array.rb
aber Sie können es überall platzieren, was beim Booten usw. enthalten ist.config/initializers/array.rb
quelle
quelle
Löst Division durch Null, Integer Division und ist leicht zu lesen. Kann leicht geändert werden, wenn ein leeres Array 0 zurückgibt.
Ich mag diese Variante auch, aber sie ist etwas wortreicher.
quelle
quelle
Diese Methode kann hilfreich sein.
quelle
Ohne das Array wiederholen zu müssen (zB perfekt für Einzeiler):
quelle
Kurz, aber mit Instanzvariable
quelle
a_size = nil; [1,2].tap { |a| a_size = a.size }.inject(:+).to_f/a_size
lieber eine Instanzvariable erstellen.Sie könnten Folgendes ausprobieren:
quelle