Ich habe eine Liste beliebiger Länge, und ich muss sie in gleich große Stücke aufteilen und sie bearbeiten. Es gibt einige offensichtliche Möglichkeiten, dies zu tun, z. B. einen Zähler und zwei Listen zu führen. Wenn die zweite Liste voll ist, fügen Sie sie der ersten Liste hinzu und leeren Sie die zweite Liste für die nächste Datenrunde. Dies ist jedoch möglicherweise extrem teuer.
Ich habe mich gefragt, ob jemand eine gute Lösung für Listen beliebiger Länge hat, z. B. mit Generatoren.
Ich suchte nach etwas Nützlichem itertools
, konnte aber nichts offensichtlich Nützliches finden. Könnte es aber verpasst haben.
Verwandte Frage: Was ist die "pythonischste" Methode, um eine Liste in Blöcken zu durchlaufen?
Antworten:
Hier ist ein Generator, der die gewünschten Chunks liefert:
Wenn Sie Python 2 verwenden, sollten Sie
xrange()
anstelle vonrange()
:Sie können auch einfach das Listenverständnis verwenden, anstatt eine Funktion zu schreiben. Es ist jedoch eine gute Idee, Operationen wie diese in benannten Funktionen zu kapseln, damit Ihr Code leichter zu verstehen ist. Python 3:
Python 2-Version:
quelle
Wenn Sie etwas ganz Einfaches wollen:
Verwenden Sie
xrange()
anstelle vonrange()
im Fall von Python 2.x.quelle
max()
.Direkt aus der (alten) Python-Dokumentation (Rezepte für itertools):
Die aktuelle Version, wie von JFSebastian vorgeschlagen:
Ich denke, Guidos Zeitmaschine funktioniert - hat funktioniert - wird funktionieren - wird funktioniert haben - hat wieder funktioniert.
Diese Lösungen funktionieren, weil
[iter(iterable)]*n
(oder das Äquivalent in der früheren Version) ein Iterator erstellt wird, dern
in der Liste wiederholt wird .izip_longest
führt dann effektiv ein Round-Robin von "jedem" Iterator durch; Da dies derselbe Iterator ist, wird er bei jedem solchen Aufruf erweitert, was dazu führt, dass jedes dieser Zip-Roundrobin ein Tupel vonn
Elementen generiert .quelle
list(grouper(3, range(10)))
kehrt zurück[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)]
und alle Tupel haben die Länge 3. Bitte erläutern Sie Ihren Kommentar, da ich ihn nicht verstehen kann. Wie nennt man ein Ding und wie definieren Sie es als Vielfaches von 3, wenn Sie erwarten, dass Ihr Ding ein Vielfaches von 3 ist? Vielen Dank im Voraus.itertools
funktionalen Ansatz, der im Vergleich zu einer einfachen und naiven Implementierung von reinem Python einen unlesbaren Schlamml==[1, 2, 3]
dannf(*l)
gleichbedeutend ist mitf(1, 2, 3)
. Siehe diese Frage und die offizielle Dokumentation .Ich weiß, das ist ein bisschen alt, aber noch niemand erwähnt
numpy.array_split
:quelle
Ich bin überrascht , niemand hat daran gedacht, mit
iter
‚s mit zwei Argumenten :Demo:
Dies funktioniert mit jedem iterierbaren Element und erzeugt eine träge Ausgabe. Es gibt eher Tupel als Iteratoren zurück, aber ich denke, es hat trotzdem eine gewisse Eleganz. Es füllt auch nicht auf; Wenn Sie Polsterung wünschen, reicht eine einfache Variation der oben genannten aus:
Demo:
Wie bei den
izip_longest
basierten Lösungen werden auch bei den oben genannten Pads immer Pads verwendet. Soweit ich weiß, gibt es kein ein- oder zweizeiliges itertools-Rezept für eine Funktion, die optional aufgefüllt werden kann. Durch die Kombination der beiden oben genannten Ansätze kommt dieser ziemlich nahe:Demo:
Ich glaube, dies ist der kürzeste vorgeschlagene Chunker, der eine optionale Polsterung bietet.
Wie Tomasz Gandor feststellte , werden die beiden Padding-Chunker unerwartet anhalten, wenn sie auf eine lange Folge von Pad-Werten stoßen. Hier ist eine letzte Variante, die dieses Problem auf vernünftige Weise umgeht:
Demo:
quelle
islice(it, size)
ausgedacht und ihn (wie ich es getan hatte) in ein Schleifenkonstrukt eingebettet. Nur Sie haben an die Version mit zwei Argumenten von gedacht (von deriter()
ich nichts wusste), die sie super elegant (und wahrscheinlich am leistungswirksamsten) macht. Ich hatte keine Ahnung, dass sich das erste Argument initer
eine 0-Argument-Funktion ändert, wenn der Sentinel angegeben wird. Sie geben einen (pot. Infinite) Iterator von Chunks zurück, können einen (pot. Infinite) Iterator als Eingabe verwenden, haben keinelen()
und keine Array-Slices. Genial!it
Iterator. Zweitens und am wichtigsten - Sie werden vorzeitig enden, wenn ein Teil vonpadval
tatsächlich in Ihrem Iterator vorhanden ist und verarbeitet werden sollte.izip_longest
Ansatz sein würde - ich vermute, dass dies ein komplexer Kompromiss sein könnte. Aber ... wird daspadval
Problem nicht von jeder Antwort hier geteilt, die einenpadval
Parameter bietet ?()
als Sentinel, tut richtig Arbeit Dies liegt daran.tuple(islice(it, size))
Ausbeuten ,()
wennit
leer.)Hier ist ein Generator, der mit beliebigen Iterablen arbeitet:
Beispiel:
quelle
quelle
map(None, iter)
gleichizip_longest(iter)
.*
Iterator-Tupel vor dir erklären ? Möglicherweise in Ihrem Antworttext, aber ich habe gesehen,*
dass dies in Python zuvor so verwendet wurde. Vielen Dank!Einfach und doch elegant
oder wenn Sie es vorziehen:
quelle
1
undl
sind nicht zu unterscheiden. Wie sind0
undO
. Und manchmal sogarI
und1
.print [l[x:x+10] for x in xrange(1, len(l), 10)]
range
.Kritik anderer Antworten hier:
Keine dieser Antworten ist gleich groß, sie alle hinterlassen am Ende einen kleinen Teil, sodass sie nicht vollständig ausbalanciert sind. Wenn Sie diese Funktionen zum Verteilen von Arbeit verwenden, haben Sie die Aussicht eingebaut, dass einer wahrscheinlich weit vor den anderen fertig wird, sodass er herumsteht und nichts tut, während die anderen weiter hart arbeiten.
Zum Beispiel endet die aktuelle Top-Antwort mit:
Ich hasse diesen Zwerg am Ende einfach!
Andere mögen
list(grouper(3, xrange(7)))
undchunk(xrange(7), 3)
beide kehren zurück :[(0, 1, 2), (3, 4, 5), (6, None, None)]
. DieNone
sind nur Polsterung und meiner Meinung nach eher unelegant. Sie teilen die Iterables NICHT gleichmäßig auf.Warum können wir diese nicht besser teilen?
Meine Lösung (en)
Hier ist eine ausgewogene Lösung, angepasst von einer Funktion , die ich in der Produktion verwendet habe (Hinweis in Python 3 zu ersetzen
xrange
mitrange
):Und ich habe einen Generator erstellt, der dasselbe tut, wenn Sie ihn in eine Liste aufnehmen:
Und schließlich, da ich sehe, dass alle oben genannten Funktionen Elemente in einer zusammenhängenden Reihenfolge zurückgeben (wie sie angegeben wurden):
Ausgabe
Um sie zu testen:
Welches druckt aus:
Beachten Sie, dass der zusammenhängende Generator Blöcke in den gleichen Längenmustern wie die beiden anderen bereitstellt, die Elemente jedoch alle in Ordnung sind und so gleichmäßig aufgeteilt sind, wie man eine Liste diskreter Elemente teilen kann.
quelle
list(grouper(3, xrange(7)))
und der zweite gebenchunk(xrange(7), 3)
beide zurück :[(0, 1, 2), (3, 4, 5), (6, None, None)]
. DieNone
sind nur Polsterung und meiner Meinung nach eher unelegant. Sie teilen die Iterables NICHT gleichmäßig auf. Danke für Ihre Stimme!import pandas as pd; [pd.DataFrame(np.arange(7))[i::3] for i in xrange(3)]
Ich habe die beeindruckendste Python-Antwort in einem Duplikat dieser Frage gesehen:
Sie können n-Tupel für jedes n erstellen. Wenn ja
a = range(1, 15)
, dann ist das Ergebnis:Wenn die Liste gleichmäßig aufgeteilt wird, dann können Sie ersetzen
zip_longest
mitzip
, da sonst die Triplett(13, 14, None)
wäre verloren. Python 3 wird oben verwendet. Verwenden Sie für Python 2izip_longest
.quelle
zip(i, i, i, ... i)
Mit "chunk_size" können Argumente für zip () wie folgt geschrieben werden:zip(*[i]*chunk_size)
Ob das eine gute Idee ist oder nicht, ist natürlich umstritten.zip_longest
sollte verwendet werden, wie in: stackoverflow.com/a/434411/1959808range(1, 15)
fehlt bereits Elemente, weil es 14 Elemente gibtrange(1, 15)
, nicht 15.Wenn Sie die Listengröße kennen:
Wenn nicht (ein Iterator):
Im letzteren Fall kann es schöner umformuliert werden, wenn Sie sicher sein können, dass die Sequenz immer eine ganze Anzahl von Blöcken einer bestimmten Größe enthält (dh es gibt keinen unvollständigen letzten Block).
quelle
Die Toolz- Bibliothek hat folgende
partition
Funktion:quelle
Wenn Sie beispielsweise eine Blockgröße von 3 hätten, könnten Sie Folgendes tun:
Quelle: http://code.activestate.com/recipes/303060-group-a-list-into-sequential-n-tuples/
Ich würde dies verwenden, wenn meine Blockgröße eine feste Zahl ist, die ich eingeben kann, z. B. '3', und würde mich nie ändern.
quelle
Ich mag die von tzot und JFSebastian vorgeschlagene Version des Python-Dokuments sehr, aber sie hat zwei Mängel:
Ich benutze dieses häufig in meinem Code:
UPDATE: Eine faule Chunks-Version:
quelle
while True
Schleife?StopIteration
, wenn dastuple
leer ist unditerable.next()
ausgeführt wird. Funktioniert jedoch nicht richtig in modernem Python, wo das Beenden eines Generators durchgeführt werden solltereturn
, nicht das ErhöhenStopIteration
. EINtry/except StopIteration: return
Rundum- Schleife (und der Wechseliterable.next()
zunext(iterable)
für eine versionübergreifende Kompatibilität) behebt dies mit minimalem Overhead.Wenn AA ein Array ist, ist SS die Blockgröße. Zum Beispiel:
quelle
Ich war neugierig auf die Leistung verschiedener Ansätze und hier ist es:
Getestet auf Python 3.5.1
Ergebnisse:
quelle
time
Bibliothek ist keine gute Idee, wenn wirtimeit
Modul habenCode:
Ergebnis:
quelle
Sie können die
get_chunks
Funktion derutilspie
Bibliothek auch wie folgt verwenden:Sie können
utilspie
über pip installieren :Haftungsausschluss: Ich bin der Schöpfer der Utilspie- Bibliothek .
quelle
An diesem Punkt denke ich, dass wir einen rekursiven Generator brauchen , nur für den Fall ...
In Python 2:
In Python 3:
Im Falle einer massiven Alien-Invasion kann auch ein dekorierter rekursiver Generator nützlich sein:
quelle
Mit Zuweisungsausdrücken in Python 3.8 wird es ganz nett:
Dies funktioniert mit einer beliebigen iterierbaren Datei, nicht nur mit einer Liste.
quelle
heh, einzeilige Version
quelle
def chunk
statt resultierende Funktionsobjektchunk=lambda
hat das Attribut'__ name__ 'chunk' anstelle von '<lambda>'. Der spezifische Name ist in Tracebacks nützlicher.<lamba>
oder nicht, ist zumindest ein bemerkenswerter Unterschied.Verwendungszweck:
quelle
Eine weitere explizitere Version.
quelle
Ohne len () aufzurufen, was für große Listen gut ist:
Und das ist für iterables:
Der funktionelle Geschmack der oben genannten:
ODER:
ODER:
quelle
len()
große Listen zu meiden . Es ist eine Operation mit konstanter Zeit.Hier ist eine Liste zusätzlicher Ansätze:
Gegeben
Code
Die Standardbibliothek
more_itertools
+Verweise
zip_longest
( verwandter Beitrag , verwandter Beitrag )setdefault
(Für geordnete Ergebnisse ist Python 3.6+ erforderlich.)collections.defaultdict
(Für geordnete Ergebnisse ist Python 3.6+ erforderlich.)more_itertools.chunked
( verwandte gepostet )more_itertools.sliced
more_itertools.grouper
( verwandter Beitrag )more_itertools.windowed
(siehe auchstagger
,zip_offset
)+ Eine Drittanbieter-Bibliothek, die itertools-Rezepte und mehr implementiert .
> pip install more_itertools
quelle
Siehe diese Referenz
Python3
quelle
zip(*[iter(range(7))]*3)
nur zurückgegeben[(0, 1, 2), (3, 4, 5)]
und6
die Eingabe vergessen.Da reden alle hier über Iteratoren.
boltons
hat die perfekte Methode dafür, genanntiterutils.chunked_iter
.Ausgabe:
Aber wenn Sie nicht dem Gedächtnis gnädig sein wollen, können Sie Old-Way verwenden und das Ganze
list
in erster Linie mit speicherniterutils.chunked
.quelle
Noch eine Lösung
quelle
quelle
Erwägen Sie die Verwendung von matplotlib.cbook Teilen
zum Beispiel:
quelle