Wie hast du eine Liste in gleichgroße Stücke aufgeteilt?

Ich habe eine Liste von willkürlichen Länge, und ich muss es in gleich große Stücke aufteilen und darauf operieren. Es gibt einige offensichtliche Möglichkeiten, dies zu tun, wie das Halten eines Zählers und zwei Listen, und wenn die zweite Liste füllt, fügen Sie es in die erste Liste und leeren Sie die zweite Liste für die nächste Runde der Daten, aber das ist möglicherweise extrem teuer.

Ich habe mich gefragt, ob jemand eine gute Lösung dafür für Listen von beliebiger Länge, zB mit Generatoren.

Ich suchte etwas Nützliches in itertools aber ich konnte nichts offensichtlich nützlich finden. Vielleicht habe ich es vermisst.

Zugehörige Frage: Was ist der "pythonischste" Weg, um über eine Liste in Chunks zu iterieren?

11 Solutions collect form web for “Wie hast du eine Liste in gleichgroße Stücke aufgeteilt?”

Hier ist ein Generator, der die Brocken liefert, die du möchtest:

 def chunks(l, n): """Yield successive n-sized chunks from l.""" for i in range(0, len(l), n): yield l[i:i + n] 

 import pprint pprint.pprint(list(chunks(range(10, 75), 10))) [[10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [20, 21, 22, 23, 24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], [40, 41, 42, 43, 44, 45, 46, 47, 48, 49], [50, 51, 52, 53, 54, 55, 56, 57, 58, 59], [60, 61, 62, 63, 64, 65, 66, 67, 68, 69], [70, 71, 72, 73, 74]] 

Wenn du Python 2 benutzt hast, solltest du xrange() anstelle von range() :

 def chunks(l, n): """Yield successive n-sized chunks from l.""" for i in xrange(0, len(l), n): yield l[i:i + n] 

Auch kannst du einfach das Listenverständnis verwenden, anstatt eine Funktion zu schreiben. Python 3:

 [l[i:i + n] for i in range(0, len(l), n)] 

Python 2 Version:

 [l[i:i + n] for i in xrange(0, len(l), n)] 

Wenn Sie etwas Super einfaches wollen:

 def chunks(l, n): n = max(1, n) return (l[i:i+n] for i in xrange(0, len(l), n)) 

Direkt aus der (alten) Python-Dokumentation (Rezepte für Itertools):

 from itertools import izip, chain, repeat def grouper(n, iterable, padvalue=None): "grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')" return izip(*[chain(iterable, repeat(padvalue, n-1))]*n) 

Die aktuelle Version, wie von JFSebastian vorgeschlagen:

 from itertools import izip_longest # for Python 2.x #from itertools import zip_longest # for Python 3.x #from six.moves import zip_longest # for both (uses the six compat library) def grouper(n, iterable, padvalue=None): "grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')" return izip_longest(*[iter(iterable)]*n, fillvalue=padvalue) 

Ich vermute, Guido's Zeitmaschine arbeitet – gearbeitet – wird Arbeit – wird gearbeitet haben – war wieder funktioniert.

Diese Lösungen funktionieren, weil [iter(iterable)]*n (oder das Äquivalent in der früheren Version) einen Iterator erzeugt, der n mal in der Liste wiederholt wird. izip_longest dann effektiv ein Round-Robin von "jedem" Iterator durch; Weil dies der gleiche Iterator ist, wird es von jedem solchen Aufruf vorgerückt, was zu jedem solchen Zip-Roundrobin führt ein Tupel von n Items.

Hier ist ein Generator, der auf beliebigen iterables arbeitet:

 def split_seq(iterable, size): it = iter(iterable) item = list(itertools.islice(it, size)) while item: yield item item = list(itertools.islice(it, size)) 

Beispiel:

 >>> import pprint >>> pprint.pprint(list(split_seq(xrange(75), 10))) [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [20, 21, 22, 23, 24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], [40, 41, 42, 43, 44, 45, 46, 47, 48, 49], [50, 51, 52, 53, 54, 55, 56, 57, 58, 59], [60, 61, 62, 63, 64, 65, 66, 67, 68, 69], [70, 71, 72, 73, 74]] 

Ich weiß, das ist irgendwie alt, aber ich weiß nicht, warum niemand erwähnt numpy.array_split :

 lst = range(50) In [26]: np.array_split(b,5) Out[26]: [array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]), array([20, 21, 22, 23, 24, 25, 26, 27, 28, 29]), array([30, 31, 32, 33, 34, 35, 36, 37, 38, 39]), array([40, 41, 42, 43, 44, 45, 46, 47, 48, 49])] 
 def chunk(input, size): return map(None, *([iter(input)] * size)) 

Ich bin überrascht, dass niemand daran gedacht hat, die Zwei-Argument-Form von iter :

 from itertools import islice def chunk(it, size): it = iter(it) return iter(lambda: tuple(islice(it, size)), ()) 

Demo:

 >>> list(chunk(range(14), 3)) [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13)] 

Dies funktioniert mit jedem iterable und produziert Ausgabe faul. Es gibt Tupel eher als Iteratoren, aber ich denke, es hat eine gewisse Eleganz trotzdem. Es ist auch nicht aufgesetzt; Wenn du Polsterung willst, genügt eine einfache Variation auf die oben genannte:

 from itertools import islice, chain, repeat def chunk_pad(it, size, padval=None): it = chain(iter(it), repeat(padval)) return iter(lambda: tuple(islice(it, size)), (padval,) * size) 

Demo:

 >>> list(chunk_pad(range(14), 3)) [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, None)] >>> list(chunk_pad(range(14), 3, 'a')) [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 'a')] 

Wie die izip_longest basierte Lösungen, die oben immer pads. Soweit ich weiß, gibt es keine ein-oder zwei-line-itertools Rezept für eine Funktion, die optional pads. Durch die Kombination der beiden oben genannten Ansätze, kommt dieser ziemlich nah:

 _no_padding = object() def chunk(it, size, padval=_no_padding): if padval == _no_padding: it = iter(it) sentinel = () else: it = chain(iter(it), repeat(padval)) sentinel = (padval,) * size return iter(lambda: tuple(islice(it, size)), sentinel) 

Demo:

 >>> list(chunk(range(14), 3)) [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13)] >>> list(chunk(range(14), 3, None)) [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, None)] >>> list(chunk(range(14), 3, 'a')) [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 'a')] 

Ich glaube, das ist die kürzeste Chunker vorgeschlagen, dass optionale Polsterung bietet.

Einfach und doch elegant

 l = range(1, 1000) print [l[x:x+10] for x in xrange(0, len(l), 10)] 

Oder wenn Sie es vorziehen:

 chunks = lambda l, n: [l[x: x+n] for x in xrange(0, len(l), n)] chunks(l, 10) 

Ich sah die schönste Python-ish Antwort in einem Duplikat dieser Frage:

 from itertools import zip_longest a = range(1, 16) i = iter(a) r = list(zip_longest(i, i, i)) >>> print(r) [(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12), (13, 14, 15)] 

Du kannst n-Tupel für jedes n erstellen. Wenn a = range(1, 15) , dann ist das Ergebnis:

 [(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12), (13, 14, None)] 

Wenn die Liste gleichmäßig aufgeteilt ist, dann kannst du zip_longest durch zip ersetzen, sonst wäre das Triplet (13, 14, None) verloren. Python 3 wird oben verwendet. Für Python 2, izip_longest .

More-itertools hat einen chunks iterator.

Es hat auch viel mehr Dinge, einschließlich aller Rezepte in der itertools Dokumentation.

Kritik an anderen Antworten hier:

Keine dieser Antworten sind gleichmäßig große Stücke, sie alle lassen ein Runt Chunk am Ende, also sind sie nicht völlig ausgeglichen. Wenn du diese Funktionen benutzt hast, um die Arbeit zu verteilen, hast du die Aussicht auf eine voraussichtliche Beendigung gut vor den anderen, so dass es sitzen würde, um nichts zu tun, während die anderen weiter hart arbeiten.

Zum Beispiel endet die aktuelle Top-Antwort mit:

 [60, 61, 62, 63, 64, 65, 66, 67, 68, 69], [70, 71, 72, 73, 74]] 

Ich hasse nur das Rauschen am Ende!

Andere, wie list(grouper(3, xrange(7))) und chunk(xrange(7), 3) beide zurück: [(0, 1, 2), (3, 4, 5), (6, None, None)] . Die None sind nur Polsterung, und ziemlich unelegant meiner Meinung nach. Sie sind nicht gleichmäßig Chunking die iterables.

Warum können wir das 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, um xrange mit range zu ersetzen):

 def baskets_from(items, maxbaskets=25): baskets = [[] for _ in xrange(maxbaskets)] # in Python 3 use range for i, item in enumerate(items): baskets[i % maxbaskets].append(item) return filter(None, baskets) 

Und ich habe einen Generator erstellt, der das gleiche tut, wenn man ihn in eine Liste steckt:

 def iter_baskets_from(items, maxbaskets=3): '''generates evenly balanced baskets from indexable iterable''' item_count = len(items) baskets = min(item_count, maxbaskets) for x_i in xrange(baskets): yield [items[y_i] for y_i in xrange(x_i, item_count, baskets)] 

Und schließlich, da ich sehe, dass alle oben genannten Funktionen Elemente in einer zusammenhängenden Reihenfolge zurückgeben (wie sie gegeben wurden):

 def iter_baskets_contiguous(items, maxbaskets=3, item_count=None): ''' generates balanced baskets from iterable, contiguous contents provide item_count if providing a iterator that doesn't support len() ''' item_count = item_count or len(items) baskets = min(item_count, maxbaskets) items = iter(items) floor = item_count // baskets ceiling = floor + 1 stepdown = item_count % baskets for x_i in xrange(baskets): length = ceiling if x_i < stepdown else floor yield [items.next() for _ in xrange(length)] 

Ausgabe

Um sie auszuprobieren:

 print(baskets_from(xrange(6), 8)) print(list(iter_baskets_from(xrange(6), 8))) print(list(iter_baskets_contiguous(xrange(6), 8))) print(baskets_from(xrange(22), 8)) print(list(iter_baskets_from(xrange(22), 8))) print(list(iter_baskets_contiguous(xrange(22), 8))) print(baskets_from('ABCDEFG', 3)) print(list(iter_baskets_from('ABCDEFG', 3))) print(list(iter_baskets_contiguous('ABCDEFG', 3))) print(baskets_from(xrange(26), 5)) print(list(iter_baskets_from(xrange(26), 5))) print(list(iter_baskets_contiguous(xrange(26), 5))) 

Was ausdruckt:

 [[0], [1], [2], [3], [4], [5]] [[0], [1], [2], [3], [4], [5]] [[0], [1], [2], [3], [4], [5]] [[0, 8, 16], [1, 9, 17], [2, 10, 18], [3, 11, 19], [4, 12, 20], [5, 13, 21], [6, 14], [7, 15]] [[0, 8, 16], [1, 9, 17], [2, 10, 18], [3, 11, 19], [4, 12, 20], [5, 13, 21], [6, 14], [7, 15]] [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14], [15, 16, 17], [18, 19], [20, 21]] [['A', 'D', 'G'], ['B', 'E'], ['C', 'F']] [['A', 'D', 'G'], ['B', 'E'], ['C', 'F']] [['A', 'B', 'C'], ['D', 'E'], ['F', 'G']] [[0, 5, 10, 15, 20, 25], [1, 6, 11, 16, 21], [2, 7, 12, 17, 22], [3, 8, 13, 18, 23], [4, 9, 14, 19, 24]] [[0, 5, 10, 15, 20, 25], [1, 6, 11, 16, 21], [2, 7, 12, 17, 22], [3, 8, 13, 18, 23], [4, 9, 14, 19, 24]] [[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20], [21, 22, 23, 24, 25]] 

Beachten Sie, dass der zusammenhängende Generator Chunks in der gleichen Länge Muster wie die beiden anderen, aber die Elemente sind alle in Ordnung, und sie sind so gleichmäßig geteilt, wie man eine Liste von diskreten Elementen teilen können.

  • Regex oder andere Weise, Daten aus einer Zeile mit variablen Eintrag zu holen
  • Machen Sie Python-Sublisten aus einer Liste mit einem Separator
  • Verwandeln Sie Komma getrennte Zeichenfolge in eine Liste, aber ignorieren Sie Komma in Anführungszeichen
  • Nur Skripts aus HTML-Datei erhalten
  • Python regex spaltete alle \ W + mit einigen Ausnahmen
  • In Python, wie sollte man den zweitletzten Verzeichnisnamen in einem Pfad extrahieren?
  • Aufteilen einer Textdatei basierend auf ihrem Inhalt
  • Stoppen von Medienstrom im HTML5-Webserver für webbasierte Chat- / Videokonferenzanwendung
  • Wie man eine Byte-String in separate Bytes in Python aufteilt
  • Split CSV-Datei mit Python zeigt nicht alle Daten in Excel
  • Split Text in Textdatei auf der Grundlage von Komma und Raum (Python)
  • Python ist die beste Programmiersprache der Welt.