Ich habe ein Python-Skript, das eine Liste von ganzen Zahlen als Eingabe übernimmt, die ich zum Arbeiten mit vier ganzen Zahlen auf einmal verwenden muss. Leider habe ich keine Kontrolle über die Eingabe, oder ich würde sie als Liste von Tupeln mit vier Elementen übergeben. Derzeit iteriere ich so:
for i in xrange(0, len(ints), 4):
# dummy op for example code
foo += ints[i] * ints[i + 1] + ints[i + 2] * ints[i + 3]
Es sieht jedoch sehr nach "C-think" aus, was mich vermuten lässt, dass es eine eher pythonische Art gibt, mit dieser Situation umzugehen. Die Liste wird nach Iteration gelöscht und muss daher nicht beibehalten werden. Vielleicht wäre so etwas besser?
while ints:
foo += ints[0] * ints[1] + ints[2] * ints[3]
ints[0:4] = []
Trotzdem fühlt es sich nicht ganz richtig an. : - /
Verwandte Frage: Wie teilt man in Python eine Liste in gleich große Brocken auf?
Aus dem Abschnitt recipes von Python's itertools docs geändert:
from itertools import izip_longest
def grouper(iterable, n, fillvalue=None):
args = [iter(iterable)] * n
return izip_longest(*args, fillvalue=fillvalue)
Beispiel
Im Pseudocode, um das Beispiel knapp zu halten.
grouper('ABCDEFG', 3, 'x') --> 'ABC' 'DEF' 'Gxx'
Hinweis:izip_longest
ist neu in Python 2.6. In Python 3 verwenden Sie Zip_longest
.
def chunker(seq, size):
return (seq[pos:pos + size] for pos in range(0, len(seq), size))
# (in python 2 use xrange() instead of range() to avoid allocating a list)
Einfach. Einfach. Schnell. Funktioniert mit jeder Sequenz:
text = "I am a very, very helpful text"
for group in chunker(text, 7):
print repr(group),
# 'I am a ' 'very, v' 'ery hel' 'pful te' 'xt'
print '|'.join(chunker(text, 10))
# I am a ver|y, very he|lpful text
animals = ['cat', 'dog', 'rabbit', 'duck', 'bird', 'cow', 'gnu', 'fish']
for group in chunker(animals, 3):
print group
# ['cat', 'dog', 'rabbit']
# ['duck', 'bird', 'cow']
# ['gnu', 'fish']
Ich bin ein Fan von
chunkSize= 4
for i in xrange(0, len(ints), chunkSize):
chunk = ints[i:i+chunkSize]
# process chunk of size <= chunkSize
import itertools
def chunks(iterable,size):
it = iter(iterable)
chunk = Tuple(itertools.islice(it,size))
while chunk:
yield chunk
chunk = Tuple(itertools.islice(it,size))
# though this will throw ValueError if the length of ints
# isn't a multiple of four:
for x1,x2,x3,x4 in chunks(ints,4):
foo += x1 + x2 + x3 + x4
for chunk in chunks(ints,4):
foo += sum(chunk)
Ein anderer Weg:
import itertools
def chunks2(iterable,size,filler=None):
it = itertools.chain(iterable,itertools.repeat(filler,size-1))
chunk = Tuple(itertools.islice(it,size))
while len(chunk) == size:
yield chunk
chunk = Tuple(itertools.islice(it,size))
# x2, x3 and x4 could get the value 0 if the length is not
# a multiple of 4.
for x1,x2,x3,x4 in chunks2(ints,4,0):
foo += x1 + x2 + x3 + x4
from itertools import izip_longest
def chunker(iterable, chunksize, filler):
return izip_longest(*[iter(iterable)]*chunksize, fillvalue=filler)
Ich brauchte eine Lösung, die auch mit Sets und Generatoren funktioniert. Ich konnte mir nichts sehr kurzes und hübsches vorstellen, aber es ist zumindest lesbar.
def chunker(seq, size):
res = []
for el in seq:
res.append(el)
if len(res) == size:
yield res
res = []
if res:
yield res
Liste:
>>> list(chunker([i for i in range(10)], 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
Einstellen:
>>> list(chunker(set([i for i in range(10)]), 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
Generator:
>>> list(chunker((i for i in range(10)), 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
Die ideale Lösung für dieses Problem funktioniert mit Iteratoren (nicht nur mit Sequenzen). Es sollte auch schnell gehen.
Dies ist die Lösung aus der Dokumentation für itertools:
def grouper(n, iterable, fillvalue=None):
#"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return itertools.izip_longest(fillvalue=fillvalue, *args)
Mit ipythons %timeit
auf meinem Mac Book Air erhalte ich 47,5 us pro Schleife.
Dies funktioniert jedoch nicht wirklich für mich, da die Ergebnisse zu Gruppen in gleichgroßer Größe gepolstert werden. Eine Lösung ohne Polsterung ist etwas komplizierter. Die naivste Lösung könnte sein:
def grouper(size, iterable):
i = iter(iterable)
while True:
out = []
try:
for _ in range(size):
out.append(i.next())
except StopIteration:
yield out
break
yield out
Einfach, aber ziemlich langsam: 693 us pro Loop
Die beste Lösung, die ich mit islice
für die innere Schleife entwickeln könnte:
def grouper(size, iterable):
it = iter(iterable)
while True:
group = Tuple(itertools.islice(it, None, size))
if not group:
break
yield group
Mit dem gleichen Datensatz bekomme ich 305 US-Dollar pro Schleife.
Kann eine reine Lösung nicht schneller als diese erhalten werden, gebe ich die folgende Lösung mit einem wichtigen Vorbehalt: Wenn Ihre Eingabedaten Instanzen von filldata
enthalten, könnten Sie eine falsche Antwort erhalten.
def grouper(n, iterable, fillvalue=None):
#"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
for i in itertools.izip_longest(fillvalue=fillvalue, *args):
if Tuple(i)[-1] == fillvalue:
yield Tuple(v for v in i if v != fillvalue)
else:
yield i
Ich mag diese Antwort wirklich nicht, aber sie ist wesentlich schneller. 124 uns pro Schleife
Die Verwendung von map () anstelle von zip () behebt das Auffüllproblem in der Antwort von J. F. Sebastian:
>>> def chunker(iterable, chunksize):
... return map(None,*[iter(iterable)]*chunksize)
Beispiel:
>>> s = '1234567890'
>>> chunker(s, 3)
[('1', '2', '3'), ('4', '5', '6'), ('7', '8', '9'), ('0', None, None)]
>>> chunker(s, 4)
[('1', '2', '3', '4'), ('5', '6', '7', '8'), ('9', '0', None, None)]
>>> chunker(s, 5)
[('1', '2', '3', '4', '5'), ('6', '7', '8', '9', '0')]
Ähnlich wie bei anderen Vorschlägen, aber nicht genau identisch, mache ich es gerne so, weil es einfach und leicht zu lesen ist:
it = iter([1, 2, 3, 4, 5, 6, 7, 8, 9])
for chunk in Zip(it, it, it, it):
print chunk
>>> (1, 2, 3, 4)
>>> (5, 6, 7, 8)
Auf diese Weise erhalten Sie nicht den letzten Teilblock. Wenn Sie (9, None, None, None)
als letzten Abschnitt erhalten möchten, verwenden Sie einfach izip_longest
aus itertools
.
Da es bisher noch niemand erwähnt hat, ist hier eine Zip()
-Lösung:
>>> def chunker(iterable, chunksize):
... return Zip(*[iter(iterable)]*chunksize)
Es funktioniert nur, wenn die Länge Ihrer Sequenz immer durch die Chunk-Größe teilbar ist, oder Sie interessieren sich nicht für einen nachfolgenden Chunk, wenn dies nicht der Fall ist.
Beispiel:
>>> s = '1234567890'
>>> chunker(s, 3)
[('1', '2', '3'), ('4', '5', '6'), ('7', '8', '9')]
>>> chunker(s, 4)
[('1', '2', '3', '4'), ('5', '6', '7', '8')]
>>> chunker(s, 5)
[('1', '2', '3', '4', '5'), ('6', '7', '8', '9', '0')]
Oder verwenden Sie itertools.izip , um einen Iterator anstelle einer Liste zurückzugeben:
>>> from itertools import izip
>>> def chunker(iterable, chunksize):
... return izip(*[iter(iterable)]*chunksize)
Die Polsterung kann mit der Antwort von @ ΤΖΩ - korrigiert werden:
>>> from itertools import chain, izip, repeat
>>> def chunker(iterable, chunksize, fillvalue=None):
... it = chain(iterable, repeat(fillvalue, chunksize-1))
... args = [it] * chunksize
... return izip(*args)
Wenn es Ihnen nichts ausmacht, ein externes Paket zu verwenden, können Sie iteration_utilities.grouper
aus iteration_utilties
verwenden. 1. Es unterstützt alle Iterables (nicht nur Sequenzen):
from iteration_utilities import grouper
seq = list(range(20))
for group in grouper(seq, 4):
print(group)
welche druckt:
(0, 1, 2, 3)
(4, 5, 6, 7)
(8, 9, 10, 11)
(12, 13, 14, 15)
(16, 17, 18, 19)
Falls die Länge kein Vielfaches der Gruppengröße ist, unterstützt sie auch das Füllen (die unvollständige letzte Gruppe) oder das Abschneiden (Löschen der unvollständigen letzten Gruppe) der letzten:
from iteration_utilities import grouper
seq = list(range(17))
for group in grouper(seq, 4):
print(group)
# (0, 1, 2, 3)
# (4, 5, 6, 7)
# (8, 9, 10, 11)
# (12, 13, 14, 15)
# (16,)
for group in grouper(seq, 4, fillvalue=None):
print(group)
# (0, 1, 2, 3)
# (4, 5, 6, 7)
# (8, 9, 10, 11)
# (12, 13, 14, 15)
# (16, None, None, None)
for group in grouper(seq, 4, truncate=True):
print(group)
# (0, 1, 2, 3)
# (4, 5, 6, 7)
# (8, 9, 10, 11)
# (12, 13, 14, 15)
1 Haftungsausschluss: Ich bin der Autor dieses Pakets.
Kleine Funktionen und Dinge zu benutzen, gefällt mir nicht wirklich; Ich ziehe es vor, nur Scheiben zu verwenden:
data = [...]
chunk_size = 10000 # or whatever
chunks = [data[i:i+chunk_size] for i in xrange(0,len(data),chunk_size)]
for chunk in chunks:
...
Wenn die Liste groß ist, können Sie am besten einen Generator verwenden:
def get_chunk(iterable, chunk_size):
result = []
for item in iterable:
result.append(item)
if len(result) == chunk_size:
yield Tuple(result)
result = []
if len(result) > 0:
yield Tuple(result)
for x in get_chunk([1,2,3,4,5,6,7,8,9,10], 3):
print x
(1, 2, 3)
(4, 5, 6)
(7, 8, 9)
(10,)
Mit NumPy ist es einfach:
ints = array([1, 2, 3, 4, 5, 6, 7, 8])
for int1, int2 in ints.reshape(-1, 2):
print(int1, int2)
ausgabe:
1 2
3 4
5 6
7 8
Ein anderer Ansatz wäre die Verwendung der Zwei-Argument-Form von iter
:
from itertools import islice
def group(it, size):
it = iter(it)
return iter(lambda: Tuple(islice(it, size)), ())
Dies kann leicht angepasst werden, um die Polsterung zu verwenden (ähnlich wie Markus Jarderot ).
from itertools import islice, chain, repeat
def group_pad(it, size, pad=None):
it = chain(iter(it), repeat(pad))
return iter(lambda: Tuple(islice(it, size)), (pad,) * size)
Diese können für optionale Polsterung sogar kombiniert werden:
_no_pad = object()
def group(it, size, pad=_no_pad):
if pad == _no_pad:
it = iter(it)
sentinel = ()
else:
it = chain(iter(it), repeat(pad))
sentinel = (pad,) * size
return iter(lambda: Tuple(islice(it, size)), sentinel)
Sofern ich nichts vermisse, wurde die folgende einfache Lösung mit Generatorausdrücken nicht erwähnt. Es wird vorausgesetzt, dass sowohl die Größe als auch die Anzahl der Chunks bekannt sind (was häufig der Fall ist) und dass keine Polsterung erforderlich ist:
def chunks(it, n, m):
"""Make an iterator over m first chunks of size n.
"""
it = iter(it)
# Chunks are presented as tuples.
return (Tuple(next(it) for _ in range(n)) for _ in range(m))
Hier ist ein Chunker ohne Import, der Generatoren unterstützt:
def chunks(seq, size):
it = iter(seq)
while True:
ret = Tuple(it.next() for _ in range(size))
if len(ret) == size:
yield ret
else:
raise StopIteration()
Anwendungsbeispiel:
>>> def foo():
... i = 0
... while True:
... i += 1
... yield i
...
>>> c = chunks(foo(), 3)
>>> c.next()
(1, 2, 3)
>>> c.next()
(4, 5, 6)
>>> list(chunks('abcdefg', 2))
[('a', 'b'), ('c', 'd'), ('e', 'f')]
def chunker(iterable, n):
"""Yield iterable in chunk sizes.
>>> chunks = chunker('ABCDEF', n=4)
>>> chunks.next()
['A', 'B', 'C', 'D']
>>> chunks.next()
['E', 'F']
"""
it = iter(iterable)
while True:
chunk = []
for i in range(n):
try:
chunk.append(it.next())
except StopIteration:
yield chunk
raise StopIteration
yield chunk
if __== '__main__':
import doctest
doctest.testmod()
Über die Lösung gab J.F. Sebastian
hier :
def chunker(iterable, chunksize):
return Zip(*[iter(iterable)]*chunksize)
Es ist klug, hat aber einen Nachteil - immer Tuple zurückgeben. Wie bekomme ich stattdessen einen String?
Natürlich können Sie ''.join(chunker(...))
schreiben, aber das temporäre Tuple ist trotzdem konstruiert.
Sie können das temporäre Tupel loswerden, indem Sie eigene Zip
schreiben, wie folgt:
class IteratorExhausted(Exception):
pass
def translate_StopIteration(iterable, to=IteratorExhausted):
for i in iterable:
yield i
raise to # StopIteration would get ignored because this is generator,
# but custom exception can leave the generator.
def custom_Zip(*iterables, reductor=Tuple):
iterators = Tuple(map(translate_StopIteration, iterables))
while True:
try:
yield reductor(next(i) for i in iterators)
except IteratorExhausted: # when any of iterators get exhausted.
break
Dann
def chunker(data, size, reductor=Tuple):
return custom_Zip(*[iter(data)]*size, reductor=reductor)
Verwendungsbeispiel:
>>> for i in chunker('12345', 2):
... print(repr(i))
...
('1', '2')
('3', '4')
>>> for i in chunker('12345', 2, ''.join):
... print(repr(i))
...
'12'
'34'
Ich möchte nie, dass meine Brocken gefüllt sind, daher ist diese Anforderung unerlässlich. Ich finde, dass die Fähigkeit, an jedem Iterer zu arbeiten, ebenfalls erforderlich ist. Angesichts dessen habe ich mich entschlossen, die akzeptierte Antwort zu verlängern, https://stackoverflow.com/a/434411/1074659 .
Die Leistung ist bei diesem Ansatz ein kleiner Treffer, wenn die Auffüllung nicht gewünscht wird, da die aufgefüllten Werte verglichen und gefiltert werden müssen. Bei großen Stückgrößen ist dieses Dienstprogramm jedoch sehr leistungsfähig.
#!/usr/bin/env python3
from itertools import Zip_longest
_UNDEFINED = object()
def chunker(iterable, chunksize, fillvalue=_UNDEFINED):
"""
Collect data into chunks and optionally pad it.
Performance worsens as `chunksize` approaches 1.
Inspired by:
https://docs.python.org/3/library/itertools.html#itertools-recipes
"""
args = [iter(iterable)] * chunksize
chunks = Zip_longest(*args, fillvalue=fillvalue)
yield from (
filter(lambda val: val is not _UNDEFINED, chunk)
if chunk[-1] is _UNDEFINED
else chunk
for chunk in chunks
) if fillvalue is _UNDEFINED else chunks
def group_by(iterable, size):
"""Group an iterable into lists that don't exceed the size given.
>>> group_by([1,2,3,4,5], 2)
[[1, 2], [3, 4], [5]]
"""
sublist = []
for index, item in enumerate(iterable):
if index > 0 and index % size == 0:
yield sublist
sublist = []
sublist.append(item)
if sublist:
yield sublist
Bei Ihrer zweiten Methode würde ich mit der folgenden Gruppe von 4 vorrücken:
ints = ints[4:]
Ich habe jedoch keine Leistungsmessung durchgeführt, daher weiß ich nicht, welche effizienter ist.
Allerdings würde ich normalerweise die erste Methode wählen. Es ist nicht schön, aber das ist oft eine Folge der Verbindung mit der Außenwelt.
Sie können partition oder chunks - Funktion von funcy library verwenden:
from funcy import partition
for a, b, c, d in partition(4, ints):
foo += a * b * c * d
Diese Funktionen haben auch die Iterator-Versionen ipartition
und ichunks
, die in diesem Fall effizienter sind.
Sie können auch auf deren Implementierung schauen.
Ich mag diesen Ansatz. Es fühlt sich einfach und nicht magisch an, unterstützt alle iterierbaren Typen und erfordert keinen Import.
def chunk_iter(iterable, chunk_size):
it = iter(iterable)
while True:
chunk = Tuple(next(it) for _ in range(chunk_size))
if not chunk:
break
yield chunk
Noch eine Antwort, deren Vorteile sind:
1) leicht verständlich
2) Funktioniert auf allen Iterationen, nicht nur auf Sequenzen (einige der obigen Antworten werden bei Dateihandles ersticken)
3) Der Block wird nicht gleichzeitig in den Speicher geladen
4) Führt keine lange Liste von Verweisen auf denselben Iterator im Speicher aus
5) Kein Auffüllen der Füllwerte am Ende der Liste
Das heißt, ich habe es nicht zeitlich festgelegt, so dass es langsamer sein könnte als einige der intelligenteren Methoden, und einige der Vorteile können angesichts des Anwendungsfalls irrelevant sein.
def chunkiter(iterable, size):
def inneriter(first, iterator, size):
yield first
for _ in xrange(size - 1):
yield iterator.next()
it = iter(iterable)
while True:
yield inneriter(it.next(), it, size)
In [2]: i = chunkiter('abcdefgh', 3)
In [3]: for ii in i:
for c in ii:
print c,
print ''
...:
a b c
d e f
g h
Update:
Ein paar Nachteile aufgrund der Tatsache, dass die inneren und äußeren Schleifen Werte aus demselben Iterator ziehen:
1) continue funktioniert nicht wie erwartet in der äußeren Schleife - es wird einfach mit dem nächsten Element fortgefahren, anstatt einen Block zu überspringen. Dies scheint jedoch kein Problem zu sein, da in der äußeren Schleife nichts zu testen ist.
2) break funktioniert nicht wie erwartet in der inneren Schleife - die Steuerung wird in der inneren Schleife mit dem nächsten Element im Iterator wieder ausgeführt. Um ganze Brocken zu überspringen, wickeln Sie entweder den inneren Iterator (ii oben) in einen Tupel, z. for c in Tuple(ii)
, oder setzen Sie ein Flag und lassen Sie den Iterator aus.
So vermeiden Sie alle Konvertierungen in eine Liste import itertools
und:
>>> for k, g in itertools.groupby(xrange(35), lambda x: x/10):
... list(g)
Produziert:
...
0 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1 [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
2 [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
3 [30, 31, 32, 33, 34]
>>>
Ich habe groupby
überprüft, und es wird nicht in Liste konvertiert oder len
verwendet. Ich denke, dies wird die Auflösung jedes Wertes verzögern, bis er tatsächlich verwendet wird. Leider schien keine der verfügbaren Antworten (zu dieser Zeit) diese Variation zu bieten.
Wenn Sie jedes Element bearbeiten müssen, verschachteln Sie eine for-Schleife über g:
for k,g in itertools.groupby(xrange(35), lambda x: x/10):
for i in g:
# do what you need to do with individual items
# now do what you need to do with the whole group
Mein besonderes Interesse daran war die Notwendigkeit, einen Generator zu verwenden, um Änderungen von bis zu 1000 Batches an die gmail-API zu übermitteln:
messages = a_generator_which_would_not_be_smart_as_a_list
for idx, batch in groupby(messages, lambda x: x/1000):
batch_request = BatchHttpRequest()
for message in batch:
batch_request.add(self.service.users().messages().modify(userId='me', id=message['id'], body=msg_labels))
http = httplib2.Http()
self.credentials.authorize(http)
batch_request.execute(http=http)
Ganz Pythonic hier (Sie können auch den Körper der split_groups
-Funktion einbetten)
import itertools
def split_groups(iter_in, group_size):
return ((x for _, x in item) for _, item in itertools.groupby(enumerate(iter_in), key=lambda x: x[0] // group_size))
for x, y, z, w in split_groups(range(16), 4):
foo += x * y + z * w
One-Liner, Adhoc-Lösung zum Durchlaufen einer Liste x
in Chunks der Größe 4
-
for a, b, c, d in Zip(x[0::4], x[1::4], x[2::4], x[3::4]):
... do something with a, b, c and d ...
Zuerst habe ich es entworfen, um Zeichenfolgen in Teilzeichenfolgen aufzuteilen, um Zeichenfolgen zu analysieren, die Hex enthalten.
Heute habe ich daraus einen komplexen, aber immer noch einfachen Generator gemacht.
def chunker(iterable, size, reductor, condition):
it = iter(iterable)
def chunk_generator():
return (next(it) for _ in range(size))
chunk = reductor(chunk_generator())
while condition(chunk):
yield chunk
chunk = reductor(chunk_generator())
iterable
ist ein beliebiger iterierbarer Iterator/Generator, der Eingabedaten enthält/erzeugt/iteriert,size
ist natürlich die Größe des Blocks, den Sie erhalten möchten.reductor
ist eine aufrufbare Funktion, die einen Generator empfängt, der den Inhalt des Chunks durchläuft.
Ich würde erwarten, dass es Sequenz oder String zurückgibt, aber ich verlange das nicht.
Sie können als dieses Argument beispielsweise list
, Tuple
, set
, frozenset
, übergeben.
oder etwas schicker. Ich würde diese Funktion übergeben und String zurückgeben
(vorausgesetzt, dass iterable
Strings enthält/generiert/iteriert):
def concatenate(iterable):
return ''.join(iterable)
Beachten Sie, dass reductor
das Schließen des Generators verursachen kann, indem eine Ausnahme ausgelöst wird.
condition
ist eine aufrufbare Funktion, die alles empfängt, was von reductor
zurückgegeben wurde.
.__ beschließt, es zu genehmigen und zu erbringen (durch Rückgabe aller Bewertungen an True
),
oder es ablehnen und die Arbeit des Generators beenden (indem Sie etwas anderes zurückgeben oder eine Ausnahme auslösen).
Wenn die Anzahl der Elemente in iterable
nicht durch size
teilbar ist und it
erschöpft ist, erhält reductor
einen Generator, der weniger Elemente als size
generiert.
Nennen wir diese Elemente lasts elements .
Ich habe zwei Funktionen eingeladen, um dieses Argument zu übergeben:
lambda x:x
- die lasts-Elemente werden ausgegeben.
lambda x: len(x)==<size>
- das lasts-Element wird abgelehnt.
ersetzen Sie <size>
mit einer Zahl, die size
entspricht.
Diese Antwort teilt eine Liste von Strings auf , zB. Einhaltung der PEP8-Leitungslänge:
def split(what, target_length=79):
'''splits list of strings into sublists, each
having string length at most 79'''
out = [[]]
while what:
if len("', '".join(out[-1])) + len(what[0]) < target_length:
out[-1].append(what.pop(0))
else:
if not out[-1]: # string longer than target_length
out[-1] = [what.pop(0)]
out.append([])
return out
Benutzen als
>>> split(['deferred_income', 'long_term_incentive', 'restricted_stock_deferred', 'shared_receipt_with_poi', 'loan_advances', 'from_messages', 'other', 'director_fees', 'bonus', 'total_stock_value', 'from_poi_to_this_person', 'from_this_person_to_poi', 'restricted_stock', 'salary', 'total_payments', 'exercised_stock_options'], 75)
[['deferred_income', 'long_term_incentive', 'restricted_stock_deferred'], ['shared_receipt_with_poi', 'loan_advances', 'from_messages', 'other'], ['director_fees', 'bonus', 'total_stock_value', 'from_poi_to_this_person'], ['from_this_person_to_poi', 'restricted_stock', 'salary', 'total_payments'], ['exercised_stock_options']]
Es scheint keinen schönen Weg zu geben. Hier ist eine Seite mit einer Reihe von Methoden, darunter:
def split_seq(seq, size):
newseq = []
splitsize = 1.0/size*len(seq)
for i in range(size):
newseq.append(seq[int(round(i*splitsize)):int(round((i+1)*splitsize))])
return newseq
Ich hoffe, dass ich, indem ich einen Iterator aus einer Liste wende, nicht einfach ein Stück der Liste kopiere. Generatoren können in Scheiben geschnitten werden und sie werden automatisch immer noch ein Generator sein, während Listen in riesige Stücke von 1000 Einträgen geschnitten werden, was weniger effizient ist.
def iter_group(iterable, batch_size:int):
length = len(iterable)
start = batch_size*-1
end = 0
while(end < length):
start += batch_size
end += batch_size
if type(iterable) == list:
yield (iterable[i] for i in range(start,min(length-1,end)))
else:
yield iterable[start:end]
Verwendungszweck:
items = list(range(1,1251))
for item_group in iter_group(items, 1000):
for item in item_group:
print(item)
Wenn die Listen die gleiche Größe haben, können Sie sie mit Zip()
zu Listen von 4-Tupeln kombinieren. Zum Beispiel:
# Four lists of four elements each.
l1 = range(0, 4)
l2 = range(4, 8)
l3 = range(8, 12)
l4 = range(12, 16)
for i1, i2, i3, i4 in Zip(l1, l2, l3, l4):
...
Die Funktion Zip()
erzeugt Folgendes:
>>> print l1
[0, 1, 2, 3]
>>> print l2
[4, 5, 6, 7]
>>> print l3
[8, 9, 10, 11]
>>> print l4
[12, 13, 14, 15]
>>> print Zip(l1, l2, l3, l4)
[(0, 4, 8, 12), (1, 5, 9, 13), (2, 6, 10, 14), (3, 7, 11, 15)]
Wenn die Listen groß sind und Sie sie nicht zu einer größeren Liste zusammenfassen möchten, verwenden Sie itertools.izip()
, wodurch ein Iterator anstelle einer Liste erstellt wird.
from itertools import izip
for i1, i2, i3, i4 in izip(l1, l2, l3, l4):
...
Es ist leicht, itertools.groupby
dafür zu sorgen, dass Sie iterierbare Iterationen ausführen können, ohne temporäre Listen erstellen zu müssen:
groupby(iterable, (lambda x,y: (lambda z: x.next()/y))(count(),100))
Lassen Sie sich nicht von den verschachtelten Lambdas abschrecken, das äußere Lambda läuft nur einmal, um den count()
-Generator und den konstanten 100
in den Bereich des inneren Lambda zu stellen.
Ich benutze dies, um Zeilen von Zeilen an mysql zu senden.
for k,v in groupby(bigdata, (lambda x,y: (lambda z: x.next()/y))(count(),100))):
cursor.executemany(sql, v)
Warum nicht Listenverständnis verwenden?
l = [1 , 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
n = 4
filler = 0
fills = len(l) % n
chunks = ((l + [filler] * fills)[x * n:x * n + n] for x in range(int((len(l) + n - 1)/n)))
print(chunks)
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 0]]