Seite 1 von 1
Zwei iterators parallel durchlaufen, Fehler bei ungleicher Länge
Verfasst: Mittwoch 8. Januar 2020, 09:20
von Mick
Hey Leute,
ich möchte zwei iterators parallel durchlaufen. Beide sollten im Normalfall gleich lang sein und daher gleichzeitig leer sein. Ich möchte, dass der iterator automatisch einen Fehler ausgibt, wenn beide Subiteratoren nicht gleich lang sind, damit ich das später im Code nicht mehr überprüfen muss.
Ich habe diese Lösung hier gefunden, mit zip_longest aus den itertools:
https://stackoverflow.com/questions/329 ... -in-python
Code: Alles auswählen
from itertools import zip_longest
def zip_equal(*iterables):
sentinel = object()
for combo in zip_longest(*iterables, fillvalue=sentinel):
if any([c is sentinel for c in combo]):
raise ValueError('Iterables have different lengths')
yield combo
Kann mir jemand verraten warum ich dafür das sentinel object benötige? Warum kann ich nicht einfach die Standard fillvalue 'None' verwenden und das überprüfen? So:
Code: Alles auswählen
def zip_equal(*iterables):
for combo in zip_longest(*iterables):
if any([c is None for c in combo]):
raise ValueError('Iterables have different lengths')
yield combo
Danke!
Re: Zwei iterators parallel durchlaufen, Fehler bei ungleicher Länge
Verfasst: Mittwoch 8. Januar 2020, 10:00
von __deets__
Weil du dann sicherstellen musst, das None niemals ein valides Ergebnis eines der iteratoren ist. Womit das Rezept nicht wirklich generisch wäre.
Re: Zwei iterators parallel durchlaufen, Fehler bei ungleicher Länge
Verfasst: Mittwoch 8. Januar 2020, 11:20
von Sirius3
Mir gefällt ja die zweite Lösung deutlich besser.
@Mick: die eckigen Klammern bei `any` sind überflüssig, und machen die Nutzung von any auch unelegant.
Re: Zwei iterators parallel durchlaufen, Fehler bei ungleicher Länge
Verfasst: Mittwoch 8. Januar 2020, 11:27
von __deets__
Die zweite macht halt nicht das gleiche wie die erste - wenn man sich das erlauben kann ist ja gut, aber die erste ist ganz klar der Kandidat fuer die Sammlung fuer hilfreichen Kram.
Was mir an beiden nicht gefaellt ist die unnoetige list-comprehension im any-clause - da haette ich einen generator-Ausdruck gebaut.
Re: Zwei iterators parallel durchlaufen, Fehler bei ungleicher Länge
Verfasst: Mittwoch 8. Januar 2020, 11:37
von __deets__
So waere mein Entwurf, inklusive der Moeglichkeit den sentinel zu modifizieren:
Code: Alles auswählen
from itertools import zip_longest, chain, cycle
def zip_equal(*iterables, sentinel=object()):
for combo in zip_longest(*iterables, fillvalue=sentinel):
if any(c is sentinel for c in combo):
raise ValueError('Iterables have different lengths')
yield combo
for a, b in zip_equal(chain(range(3), cycle([None])), range(5)):
print(a, b)
Re: Zwei iterators parallel durchlaufen, Fehler bei ungleicher Länge
Verfasst: Mittwoch 8. Januar 2020, 18:51
von Mick
Hallo an alle,
vielen Dank für die Antworten. Dann ist es für meinen use-case in Ordnung wenn ich die Funktion ohne das Sentinel-object verwende, denn None kann ich als Ergebnis der iterators ausschließen.
Danke auch für das spotten der unnötigen list-comprehension. Hab ich ausgebaut.
Re: Zwei iterators parallel durchlaufen, Fehler bei ungleicher Länge
Verfasst: Donnerstag 9. Januar 2020, 12:11
von DeaD_EyE
Manche verwenden auch ... (Ellipsis) als Sentinel. Würde ich aber nicht verwenden, da es bei den Meisten ziemlich unbekannt ist.
Da ist die Variante mit dem eigenen Objekt viel besser und wird so auch oft angewandt.
Bei multiprocessing funktioniert das leider nicht, da die Objekte in den Prozessen unterschiedliche Identitäten haben.
Mit threading funktioniert das aber schon.
Re: Zwei iterators parallel durchlaufen, Fehler bei ungleicher Länge
Verfasst: Donnerstag 9. Januar 2020, 13:31
von __blackjack__
Das hier sollte auch bei multiprocessing funktionieren, denn das Sentinel-Objekt wird ja nur lokal in der Funktion verwendet und die läuft ja nicht über mehrere Prozesse verteilt.
Re: Zwei iterators parallel durchlaufen, Fehler bei ungleicher Länge
Verfasst: Donnerstag 9. Januar 2020, 13:47
von DeaD_EyE
__blackjack__ hat geschrieben: Donnerstag 9. Januar 2020, 13:31
Das hier sollte auch bei multiprocessing funktionieren, denn das Sentinel-Objekt wird ja nur lokal in der Funktion verwendet und die läuft ja nicht über mehrere Prozesse verteilt.
Stimmt. Das Beispiel sollte auch mit Multiprocessing funktionieren.