Ich bin überrascht, dass niemand daran gedacht hat, die iter
Zwei-Argument-Form zu verwenden:
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 gibt die Ausgabe träge aus. Es gibt Tupel zurück anstatt Iteratoren, aber ich denke, es hat dennoch eine gewisse Eleganz. Es füllt auch nicht auf; wenn Sie eine Füllung möchten, reicht eine einfache Variation des obigen aus:
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 auf izip_longest
basierenden Lösungen füllt das obige immer. Soweit ich weiß, gibt es kein ein- oder zwei-Zeilen-Itertools-Rezept für eine Funktion, die optional füllt. Durch die Kombination der obigen beiden Ansätze kommt diese ziemlich nah dran:
_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, dass dies der kürzeste vorgeschlagene Chunker ist, der optionale Füllung ermöglicht.
Wie Tomasz Gandor beobachtet hat, werden die beiden Padding-Chunker unerwartet stoppen, wenn sie auf eine lange Sequenz von Füllwerten treffen. Hier ist eine letzte Variation, die dieses Problem auf vernünftige Weise umgeht:
_no_padding = object()
def chunk(it, size, padval=_no_padding):
it = iter(it)
chunker = iter(lambda: tuple(islice(it, size)), ())
if padval == _no_padding:
yield from chunker
else:
for ch in chunker:
yield ch if len(ch) == size else ch + (padval,) * (size - len(ch))
Demo:
>>> list(chunk([1, 2, (), (), 5], 2))
[(1, 2), ((), ()), (5,)]
>>> list(chunk([1, 2, None, None, 5], 2, None))
[(1, 2), (None, None), (5, None)]
40 Stimmen
Bevor Sie eine neue Antwort veröffentlichen, beachten Sie bitte, dass es bereits mehr als 60 Antworten auf diese Frage gibt. Stellen Sie sicher, dass Ihre Antwort Informationen enthält, die nicht unter den vorhandenen Antworten sind.
3 Stimmen
Die Zeichenfolgenäquivalente dieser Frage: String alle n Zeichen teilen? (während einige Antworten sich überschneiden und für beide gelten, gibt es einige, die eindeutig sind).