Durchschnitt von zwei aufeinander folgenden Elementen in der Liste in Python
Ich habe eine Liste mit einer geraden Anzahl von float-zahlen:
[2.34, 3.45, 4.56, 1.23, 2.34, 7.89, ...].
Meine Aufgabe ist es, die Berechnung der durchschnittlichen 1-und 2-Elemente, 3 und 4, 5 und 6, usw. Was ist der kurze Weg, dies zu tun in Python?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Erklärung:
data[::2]
ist die Elemente2.34, 4.56, 2.34
data[1::2]
ist die Elemente3.45, 1.23, 7.89
zip
kombiniert Sie in ein 2-Tupel:(2.34, 3.45), (4.56, 1.23), (2.34, 7.89)
zip
- und list-comprehension! Macht die Berechnung schlank und effizient.Wenn die Liste nicht zu lang, Paul Draper, die Antwort ist einfach. Wenn es ist wirklich lange, Sie wahrscheinlich wollen zu berücksichtigen, eine der beiden anderen Optionen.
Zuerst mit Iteratoren, können Sie vermeiden, kopieren um riesige temporäre Listen:
Bedeutet dies effektiv das gleiche, aber träge, was bedeutet, es hat nur zum speichern einen Wert in einer Zeit, in Erinnerung (gut, drei Werte a, b, und der Durchschnitt) anstelle von alle von Ihnen.
iter(data)
schafft ein fauler iterator über Daten.[iter(data)]*2
erstellt eine Liste mit zwei Referenzen auf das gleiche iterator, so dass, wenn ein Fortschritt, der andere als gut.zip
und Liste Verständnis, dass Paul schon so gut erklärt. (In Python 2.x, im Gegensatz zu 3.x,zip
ist nicht faul, so sind Sie verwenden möchtenitertools.izip
eher alszip
.)Wenn Sie nicht wirklich brauchen, die Ergebnis-Liste, sondern nur etwas, das Sie Durchlaufen, ändern sich die äußeren eckigen Klammern zu Klammern, und es wird ein generator-Ausdruck, Bedeutung es gibt einen iterator statt einer Liste, und Sie sind sich nicht speichern überhaupt nichts.
Beachten Sie, dass die
itertools
docs haben ein Rezept für einegrouper
hat, der die knifflige bit (und Sie finden es auch in der third-party-Modulmehr-itertools
), so kann man nur schreibengrouper(data, 2)
stattzip(*[iter(data)]*2)
, das ist sicherlich besser lesbar, wenn Sie es Häufig. Wenn Sie möchten, eine nähere Erläuterung, siehe Wie Zackenbarsch funktioniert.Alternativ können Sie NumPy arrays anstelle von Listen:
Dann können Sie genau dies tun:
Das ist nicht nur einfacher (keine Notwendigkeit für explizite Schleifen), es ist auch etwa 10x schneller, und dauert etwa 1/4th der Speicher.
Wenn Sie generalisieren wollen, auf diese willkürliche-Länge-Gruppen...
Für die iterator-Lösung, ist es trivial:
Für die NumPy-Lösung, ist es ein bisschen schwieriger. Sie haben, um dynamisch erstellen Sie etwas iterator über
data[::size]
,data[1::size]
, ...,data[size-1::size]
wie diese:Gibt es andere Möglichkeiten, dies zu tun in NumPy, aber solange
size
ist nicht zu groß, das wird gut—und es hat den Vorteil, dass die exakt gleiche trick funktioniert für Paul Draper Lösung:avgs = [sum(vals, 0.0) / size for vals in zip(*[iter(data)]*size)]
oder ähnlichessum
statt+
) sowie... außer, dass ich denke, Ihr Kommentar sagt bereits alles, was nötig ist.np.array([1, 2, 3, 4, 5, 6]).reshape(3, 2).mean(axis=1)
?(len(data)//size, size)
, das wird schnell hässlich, so dass an diesem Punkt, ich denke, es ist Zeit zu beginnen, factoring Teile von diesem in eine Funktion.)
. Die/ size
außerhalb dersum
. Also rollte ich zurück zu ändern. (Sie können testen Sie es einfach durch das einfügen der Zeile in Ihrem interpreter.)Benutzen Sie einfach als index für die Aufgabe.
Für das einfache Beispiel,
avg2 ist, was Sie wollen. Diese vielleicht leicht zu verstehen..
list
als Variablen-name:for elem_odd, elem_even in zip( data[::2], data[1::2]): print (elem_odd + elem_even)/2.0,
ist viel schlanker.elem_odd
undelem_even
werden nur einmal gespeichert, auch wenn ich drei der Liste (wie Paul Draper ' s Antwort). Nota:zip
faul ist in Python ist3, so würde dies schaffen Sie nur zwei Listen.zip
faul ist in Python 3, aber dein code ist eindeutig Python 2, da es verwendetprint
als eine Aussage. Mittlerweile, du hast Recht, dass Sie nicht zur Schaffung von 2*N neuen Wagen, aber Sie immer noch schaffen, 3*N-Liste slots (in CPython Bedingungen, nur 2 zusätzlichePyFloatObject
s, aber 3*N extra-Zeiger). Jedenfalls kann man umgehen, indemitertools.islice
anstelle von Listen-slicing, aber ich glaube, an diesem Punkt sind Sie besser, nur die Gruppierung von iterator in den ersten Platz (wie in meiner Antwort).