Szukam fajny sposób na zip
kilka iterables podnosząc wyjątek, jeśli długość iterables nie są równe.zip iteratory zapewniające równą długość w python
W przypadku, gdy iterables są listy lub mieć metodę len
rozwiązanie to jest czyste i proste:
def zip_equal(it1, it2):
if len(it1) != len(it2):
raise ValueError("Lengths of iterables are different")
return zip(it1, it2)
Jednak jeśli it1
i it2
są generatory, poprzednia funkcja nie powiedzie się, ponieważ długość nie jest zdefiniowana TypeError: object of type 'generator' has no len()
.
Wyobrażam sobie, że moduł itertools
oferuje prosty sposób wdrożenia tego, ale jak dotąd nie udało mi się go znaleźć. I mają pochodzić z tego domowej roboty rozwiązania:
def zip_equal(it1, it2):
exhausted = False
while True:
try:
el1 = next(it1)
if exhausted: # in a previous iteration it2 was exhausted but it1 still has elements
raise ValueError("it1 and it2 have different lengths")
except StopIteration:
exhausted = True
# it2 must be exhausted too.
try:
el2 = next(it2)
# here it2 is not exhausted.
if exhausted: # it1 was exhausted => raise
raise ValueError("it1 and it2 have different lengths")
except StopIteration:
# here it2 is exhausted
if not exhausted:
# but it1 was not exhausted => raise
raise ValueError("it1 and it2 have different lengths")
exhausted = True
if not exhausted:
yield (el1, el2)
else:
return
Rozwiązaniem może być badana za pomocą następującego kodu:
it1 = (x for x in ['a', 'b', 'c']) # it1 has length 3
it2 = (x for x in [0, 1, 2, 3]) # it2 has length 4
list(zip_equal(it1, it2)) # len(it1) < len(it2) => raise
it1 = (x for x in ['a', 'b', 'c']) # it1 has length 3
it2 = (x for x in [0, 1, 2, 3]) # it2 has length 4
list(zip_equal(it2, it1)) # len(it2) > len(it1) => raise
it1 = (x for x in ['a', 'b', 'c', 'd']) # it1 has length 4
it2 = (x for x in [0, 1, 2, 3]) # it2 has length 4
list(zip_equal(it1, it2)) # like zip (or izip in python2)
jestem widokiem żadnego alternatywnego rozwiązania? Czy istnieje prostsza implementacja funkcji zip_equal
?
PS: Napisałem pytanie myśląc w Pythonie 3, ale rozwiązanie Python 2 jest również mile widziane.
Opcja 'rozwiązanie wydajność from' jest bardzo miłe. Za to i za dostarczenie dwóch różnych rozwiązań. – colidyre
Dzięki! Nawiasem mówiąc, w 'zip_longest' argumentem' fill_value' powinno być 'fillvalue' ;-). – zeehio
@zeehio: Ups, poprawione. –