Hier sind zwei Funktionen, die iterierbare Elemente in Unterlisten aufteilen. Ich glaube, dass diese Art von Aufgabe oft programmiert wird. Ich verwende sie, um Protokolldateien zu analysieren, die aus repr
Zeilen wie ('Ergebnis', 'Fall', 123, 4.56) und ('Dump', ..) und so weiter bestehen.Kann Ertrag produzieren mehrere aufeinanderfolgende Generatoren?
Ich möchte diese ändern, so dass sie Iteratoren anstelle von Listen ergeben werden. Weil die Liste ziemlich groß werden kann, aber ich kann vielleicht entscheiden, es zu nehmen oder es basierend auf den ersten paar Dingen zu überspringen. Auch wenn die Iter-Version verfügbar ist, möchte ich sie verschachteln, aber mit diesen Listen-Versionen, die etwas Speicher durch das Duplizieren von Teilen verschwenden würden.
Aber mehrere Generatoren aus einer iterierbaren Quelle abzuleiten ist für mich einfach, also bitte ich um Hilfe. Wenn möglich, möchte ich die Einführung neuer Klassen vermeiden.
Auch wenn Sie einen besseren Titel für diese Frage kennen, bitte sagen Sie mir.
Vielen Dank!
def cleave_by_mark (stream, key_fn, end_with_mark=False):
'''[f f t][t][f f] (true) [f f][t][t f f](false)'''
buf = []
for item in stream:
if key_fn(item):
if end_with_mark: buf.append(item)
if buf: yield buf
buf = []
if end_with_mark: continue
buf.append(item)
if buf: yield buf
def cleave_by_change (stream, key_fn):
'''[1 1 1][2 2][3][2 2 2 2]'''
prev = None
buf = []
for item in stream:
iden = key_fn(item)
if prev is None: prev = iden
if prev != iden:
yield buf
buf = []
prev = iden
buf.append(item)
if buf: yield buf
edit: meine eigene Antwort
auf die Antwort von jeder Dank konnte ich schreiben, was ich gefragt! Für die Funktion "cleave_for_change" könnte ich natürlich auch itertools.groupby
verwenden.
def cleave_by_mark (stream, key_fn, end_with_mark=False):
hand = []
def gen():
key = key_fn(hand[0])
yield hand.pop(0)
while 1:
if end_with_mark and key: break
hand.append(stream.next())
key = key_fn(hand[0])
if (not end_with_mark) and key: break
yield hand.pop(0)
while 1:
# allow StopIteration in the main loop
if not hand: hand.append(stream.next())
yield gen()
for cl in cleave_by_mark (iter((1,0,0,1,1,0)), lambda x:x):
print list(cl), # start with 1
# -> [1, 0, 0] [1] [1, 0]
for cl in cleave_by_mark (iter((0,1,0,0,1,1,0)), lambda x:x):
print list(cl),
# -> [0] [1, 0, 0] [1] [1, 0]
for cl in cleave_by_mark (iter((1,0,0,1,1,0)), lambda x:x, True):
print list(cl), # end with 1
# -> [1] [0, 0, 1] [1] [0]
for cl in cleave_by_mark (iter((0,1,0,0,1,1,0)), lambda x:x, True):
print list(cl),
# -> [0, 1] [0, 0, 1] [1] [0]
/
def cleave_by_change (stream, key_fn):
'''[1 1 1][2 2][3][2 2 2 2]'''
hand = []
def gen():
headkey = key_fn(hand[0])
yield hand.pop(0)
while 1:
hand.append(stream.next())
key = key_fn(hand[0])
if key != headkey: break
yield hand.pop(0)
while 1:
# allow StopIteration in the main loop
if not hand: hand.append(stream.next())
yield gen()
for cl in cleave_by_change (iter((1,1,1,2,2,2,3,2)), lambda x:x):
print list(cl),
# -> [1, 1, 1] [2, 2, 2] [3] [2]
ACHTUNG: Wenn jemand diese verwenden geht, sollten Sie die Generatoren auf jeder Ebene zu Auspuff, wie Andrew darauf hingewiesen. Denn sonst wird die äußere generatorauslösende Schleife genau dort wieder gestartet, wo der innere Generator links ist, anstatt wo der nächste "Block" beginnt.
stream = itertools.product('abc','1234', 'ABCD')
for a in iters.cleave_by_change(stream, lambda x:x[0]):
for b in iters.cleave_by_change(a, lambda x:x[1]):
print b.next()
for sink in b: pass
for sink in a: pass
('a', '1', 'A')
('b', '1', 'A')
('c', '1', 'A')
Wenn das, was Sie wollen, ist, eine Liste zu verwerfen, bevor sie zurückgegeben oder sogar bauen, durch einen Filter Argument auf die Funktionen bereitstellt, die möglich wäre. Wenn dieser Filter ein Listenpräfix zurückweist, würde die Funktion die aktuelle Ausgabeliste wegwerfen und das Anhängen an die Ausgabeliste überspringen, bis die nächste Gruppe gestartet wird. –