Wie kann man zwei Listen parallel durchlaufen?

863

Ich habe zwei iterable in Python, und ich möchte sie paarweise durchgehen:

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

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

Es sollte ergeben:

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

Eine Möglichkeit besteht darin, die Indizes zu durchlaufen:

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

Aber das scheint mir etwas unpythonisch. Gibt es einen besseren Weg, dies zu tun?

Nathan Fellman
quelle

Antworten:

1352

Python 3

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

zipstoppt, wenn der kürzere von foooder barstoppt.

In Python 3 , zip gibt einen Iterator von Tupeln, wie itertools.izipin Python2. Verwenden Sie, um eine Liste der Tupel zu erhalten list(zip(foo, bar)). Und um zu komprimieren, bis beide Iteratoren erschöpft sind, würden Sie itertools.zip_longest verwenden .

Python 2

In Python 2 , zip gibt eine Liste von Tupeln. Dies ist in Ordnung, wenn foound barnicht massiv. Wenn beide massiv sind, zip(foo,bar)ist das Formen eine unnötig massive temporäre Variable und sollte durch itertools.izipoder ersetzt werden itertools.izip_longest, was einen Iterator anstelle einer Liste zurückgibt.

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)

izipstoppt, wenn entweder foooder barerschöpft ist. izip_longeststoppt, wenn beide foound barerschöpft sind. Wenn die kürzeren Iteratoren erschöpft sind, izip_longestergibt sich ein Tupel mit Nonean der Position, die diesem Iterator entspricht. Sie können auch einen anderen Satz fillvalueaußer Nonewenn Sie es wünschen. Die ganze Geschichte finden Sie hier .


Beachten Sie auch, dass zipund sein zipähnliches brethen eine beliebige Anzahl von Iterablen als Argumente akzeptieren kann. Zum Beispiel,

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

druckt

1 red manchego
2 blue stilton
3 green brie
unutbu
quelle
@unutbu Warum sollte ich die Methode von OP der vorziehen izip(obwohl die izip/ zipviel sauberer aussieht)?
Armundle
3
Vielleicht möchten Sie zuerst Python 3 erwähnen, da es wahrscheinlich zukunftssicherer ist. Darüber hinaus ist darauf hinzuweisen, dass zip () in Python 3 genau den Vorteil hat, den nur itertools.izip () in Python 2 hatte, und daher ist dies normalerweise der richtige Weg.
Daniel S.
3
Darf ich Sie bitten, Ihre Antwort zu aktualisieren, um explizit anzugeben, dass zipund zipähnliche Funktionen itertoolseine beliebige Anzahl von Iterablen akzeptieren und nicht nur 2? Diese Frage ist jetzt kanonisch und Ihre Antwort ist die einzige, die aktualisiert werden sollte.
Vaultah
Was ist, wenn ich zusätzlich den Index möchte i? Kann ich diesen Reißverschluss in eine Aufzählung einwickeln?
Charlie Parker
2
@CharlieParker: Ja, du kannst, aber dann würdest du verwenden for i, (f, b) in enumerate(zip(foo, bar)).
Unutbu
60

Sie wollen die zipFunktion.

for (f,b) in zip(foo, bar):
    print "f: ", f ,"; b: ", b
Karl Guertin
quelle
11
Vor Python 3.0 möchten Sie verwenden, itertools.izipwenn Sie eine große Anzahl von Elementen haben.
Georg Schölly
15

Sie sollten die Zip -Funktion verwenden. Hier ist ein Beispiel, wie Ihre eigene Zip-Funktion aussehen kann

def custom_zip(seq1, seq2):
    it1 = iter(seq1)
    it2 = iter(seq2)
    while True:
        yield next(it1), next(it2)
Vlad Bezden
quelle
Hat dies nicht genau das gleiche Ergebnis wie zip(seq1, seq2)?
Niklas Mertsch
@NiklasMertsch ja es hat genau das gleiche Ergebnis. Ich habe gerade ein Beispiel gegeben, wie die Zip-Funktion aussieht
Vlad Bezden
0

Sie können die n-ten Elemente mithilfe des Verständnisses zu einem Tupel oder einer Liste bündeln und sie dann mit einer Generatorfunktion verteilen.

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.
quelle
-2

Für den Fall, dass jemand so etwas sucht, fand ich es sehr einfach und leicht:

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

Die Listen werden mit ihrem vollständigen Inhalt iteriert, im Gegensatz zu zip (), das nur bis zur minimalen Inhaltslänge iteriert.

VladiC4T
quelle
Downvoter sollten kommentieren, was sie an meinem Ansatz falsch gefunden haben oder ob er nicht als mögliche Lösung für diese Frage geeignet ist.
VladiC4T