Jak iterować po wielu listach jednocześnie? W tym BiteSize zobaczymy metodę zip i zip_longest. Kod będzie bardziej Pythonowy i pozbędziemy się kilku znaczących problemów związanych z iterowaniem po indeksach.
Standardowe iterowanie
Niestety ten standard jest bardzo powszechny w Pythonie, szczególnie u osób, które pisały wcześniej w językach C-podobnych – czyli iterujemy po indeksach. Jest to jakieś rozwiązanie i działa, także, po co się czepiać?
Ponieważ istnieje bardziej Pythonowe rozwiązanie! A to bym chciał osiągnąć, żeby nasz kod był bardziej Pythonowy.
list_a = [1, 2, 3, 4, 5] list_b = ["a", "b", "c", "d", "e"] for i in range(len(list_a)): a = list_a[i] b = list_b[i] print(a, b)
Mówiąc bardzo szczerze, iterowanie po range(len(list_a))
tylko po to, aby wyciągać elementy z tej listy to jeden z najbrzydszych sposobów iterowania po liście w Pythonie.
Natomiast, pomijając ten wątek, jakie m.in. możemy napotkać problemy?
- Liczba elementów w poszczególnych listach, może być różna – żeby sobie z tym poradzić, musimy wybrać długości obu list, zweryfikować czy są takie same i ewentualnie wybrać, która długość nam pasuje bardziej
- Co jak weźmiemy długość krótszej listy? – Nie uzyskamy wszystkich elementów dłuższej listy, w sumie nie jest jeszcze najgorzej
- Co jak trafimy na długość listy dłuższej? – Dostaniemy
IndexError
, oczywiście poradzimy sobie z tym, no ale…
Dodatkowo w kontekście pętli for należy wyciągać informację z list, po których iterujemy, co zabiera nam kolejne linie kodu.
Wykorzystanie zip
Metodę zip nie musimy znikąd importować, jest ona wbudowana w język. Ten sam kod wykorzystując metodę zip:
list_a = [1, 2, 3, 4, 5] list_b = ["a", "b", "c", "d", "e"] for a, b in zip(list_a, list_b): print(a, b)
Czysty prawda?! 🙂
Okej, ale wróćmy do problemów z poprzedniego punktu. Nie przejmujemy się długością list, natomiast jak długo będziemy iterować? – Otóż metoda zip pod spodem, wybiera NAJKRÓTSZĄ listę i iterujemy, dopóki elementy tej listy się nie skończą.
Co z elementami listy dłuższej, które ominęliśmy? Po prostu zostały pominięte.
list_a = [1, 2, 3, 4, 5] list_b = ["a", "b"] for a, b in zip(list_a, list_b): print(a, b) # Output: # 1 a # 2 b
Czemu więc wcześniej mówię, że to problem, a teraz nie? Zanim odpowiem na to pytanie zobaczmy jak działa zip_longest.
zip_longest w praktyce
Najpierw musimy zaimportować metodę z biblioteki standardowej itertools. Kod nie bardzo się zmieni, jedna lista jest dłuższa od drugiej i zamiast zip wykorzystamy zip_longest.
from itertools import zip_longest list_a = [1, 2, 3, 4] list_b = ["a", "b"] for a, b in zip_longest(list_a, list_b, fillvalue="No element here :( "): print(a, b) # Output: # 1 a # 2 b # 3 No element here :( # 4 No element here :(
Jaki będzie efekt? Tak jak wskazuje nazwa, iterujemy do najdłuższej listy (ang. longest). Natomiast tam, gdzie już nie ma elementów listy, zostanie wstawiona wartość, którą podałem w parametrze fillvalue
, czyli tekst No element here :(
. Oczywiście możemy tam wpisać cokolwiek, ale to zależy od naszego zadania. Domyślnie jest to None.
Dodatkowe przypadki
Iterowanie po dwóch listach pewnie nie robi na nikim wrażenia, a co jeżeli ma być ich więcej? Wtedy zamiast pisać:
for i in range(len(list_a)): a = list_a[i] b = list_b[i] c = list_c[i] d = list_d[i] e = list_e[i] print(a, b, c, d, e)
Możemy użyć ładniejszej (moim zdaniem) składni i napiszemy po prostu:
for a, b, c, d, e in zip(list_a, list_b, list_c, list_d, list_e): print(a, b, c, d, e)
Są też przypadki, kiedy nie chcemy rozpakowywać list do oddzielnych zmiennych, tylko trzymać je razem. Jedna grupa elementów pod tym samym indeksem, trafi do jednej tupli.
for my_tuple in zip(list_a, list_b, list_c): print(len(mytuple)) print(my_tuple)
Podsumowanie
Zip oraz zip_longest są bardzo pomocne na co dzień w iterowaniu po listach, ale także liniach pliku czy innych iterable. Należy pamiętać czy zależy nam na tym, aby wybrać wszystkie elementy, nawet jeżeli nie mają swojego „zestawu” – wtedy wykorzystujemy zip_longest. Czy chodzi nam tylko o pełne informacje i wykorzystamy zip.
W każdym razie musimy przemyśleć, na czym nam zależy i na pewno wykorzystywać to co nam oferuje język w którym piszemy 🙂
Dzięki, że dotarłeś/aś do tego momentu. Jeżeli Ci się spodobało i wiesz już coś nowego, proszę udostępnij ten wpis i blog komuś, kto też na tym skorzysta 🙂 Więcej tego typu wpisów tutaj.
Zapraszam również na mojego Instagrama, na którym też publikować będę różne treści związane z Pythonem.
Pozdrawiam i do zobaczenia, usłyszenia i kodowania
~Marek