Jak iterować równolegle dwie listy?

861

Mam dwie iterowalne wersje w Pythonie i chcę je przeglądać parami:

foo = (1, 2, 3)
bar = (4, 5, 6)

for (f, b) in some_iterator(foo, bar):
    print "f: ", f, "; b: ", b

Powinno to skutkować:

f: 1; b: 4
f: 2; b: 5
f: 3; b: 6

Jednym ze sposobów jest iteracja indeksów:

for i in xrange(len(foo)):
    print "f: ", foo[i], "; b: ", b[i]

Ale wydaje mi się to trochę niepolityczne. Czy jest na to lepszy sposób?

Nathan Fellman
źródło

Odpowiedzi:

1349

Python 3

for f, b in zip(foo, bar):
    print(f, b)

zipzatrzymuje się, gdy krótszy foolub barzatrzymuje się.

W Pythonie 3 , zip zwraca iterator krotek, jak itertools.izipw python2. Aby uzyskać listę krotek, użyj list(zip(foo, bar)). Aby skompresować plik do wyczerpania obu iteratorów, należy użyć itertools.zip_longest .

Python 2

W Pythonie 2 , zip zwraca listę krotek. To dobrze, kiedy fooi barnie są ogromne. Jeśli oba są masywne, wówczas formowanie zip(foo,bar)jest niepotrzebnie masywną zmienną tymczasową i powinno zostać zastąpione przez itertools.iziplub itertools.izip_longest, która zwraca iterator zamiast listy.

import itertools
for f,b in itertools.izip(foo,bar):
    print(f,b)
for f,b in itertools.izip_longest(foo,bar):
    print(f,b)

izipzatrzymuje się, gdy jeden foolub barjest wyczerpany. izip_longestzatrzymuje się, gdy oba fooi barsą wyczerpane. Kiedy krótsze iteratory są wyczerpane, izip_longestdaje krotkę Nonew pozycji odpowiadającej temu iteratorowi. Można również ustawić inny fillvalueoprócz Nonejeśli chcesz. Zobacz tutaj pełną historię .


Zauważ też, że zipi zippodobnie do niego, może przyjmować dowolną liczbę iterowalnych argumentów. Na przykład,

for num, cheese, color in zip([1,2,3], ['manchego', 'stilton', 'brie'], 
                              ['red', 'blue', 'green']):
    print('{} {} {}'.format(num, color, cheese))

odciski

1 red manchego
2 blue stilton
3 green brie
unutbu
źródło
@unutbu Dlaczego wolałbym metodę OP niż tę izip(nawet jeśli izip/ zipwygląda na znacznie czystszą)?
armundle
3
Możesz najpierw wspomnieć o Pythonie 3, ponieważ jest on prawdopodobnie bardziej przyszłościowy. Co więcej, * warto zauważyć, że w Pythonie 3 zip () ma dokładnie tę zaletę, że tylko itertools.izip () miał w Pythonie 2, a zatem zwykle jest to właściwy sposób.
Daniel S.
3
Czy mogę prosić o aktualizację odpowiedzi w celu wyraźnego stwierdzenia, że zipi zippodobne funkcje z itertoolsakceptowania dowolnej liczby iteracji, a nie tylko 2? To pytanie jest teraz kanoniczne, a Twoja odpowiedź jest jedyną wartą zaktualizowania.
vaultah
co jeśli dodatkowo chcę indeks i? Czy mogę owinąć ten zip w wyliczenie?
Charlie Parker,
2
@CharlieParker: Tak, możesz, ale wtedy skorzystasz for i, (f, b) in enumerate(zip(foo, bar)).
unutbu
60

Chcesz tę zipfunkcję.

for (f,b) in zip(foo, bar):
    print "f: ", f ,"; b: ", b
Karl Guertin
źródło
11
Przed wersją Python 3.0 chciałbyś użyć, itertools.izipjeśli masz dużą liczbę elementów.
Georg Schölly,
15

Powinieneś użyć funkcji „ zip ”. Oto przykład, jak może wyglądać Twoja własna funkcja zip

def custom_zip(seq1, seq2):
    it1 = iter(seq1)
    it2 = iter(seq2)
    while True:
        yield next(it1), next(it2)
Vlad Bezden
źródło
Czy to nie ma dokładnie takiego samego wyniku jak zip(seq1, seq2)?
Niklas Mertsch,
@NiklasMertsch tak, ma dokładnie ten sam wynik. Właśnie
podałem
0

Możesz połączyć n-ty element w krotkę lub listę za pomocą zrozumienia, a następnie przekazać je za pomocą funkcji generatora.

def iterate_multi(*lists):
    for i in range(min(map(len,lists))):
        yield tuple(l[i] for l in lists)

for l1, l2, l3 in iterate_multi([1,2,3],[4,5,6],[7,8,9]):
    print(str(l1)+","+str(l2)+","+str(l3))
Don F.
źródło
-2

W przypadku, gdy ktoś szuka czegoś takiego, uznałem to za bardzo proste i łatwe:

list_1 = ["Hello", "World"]
list_2 = [1, 2, 3]

for a,b in [(list_1, list_2)]:
    for element_a in a:
        ...
    for element_b in b:
        ...

>> Hello
World
1
2
3

Listy będą iterowane z pełną zawartością, w przeciwieństwie do zip (), który iteruje tylko do minimalnej długości treści.

VladiC4T
źródło
downvoters powinien skomentować to, co uważali za błędne w moim podejściu lub jeśli nie pasuje to jako możliwe rozwiązanie tego pytania.
VladiC4T