Wie kann man durch zwei Listen parallel iterieren?

Ich habe zwei Iterables 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

Das Ergebnis sollte sein:

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

Eine Möglichkeit ist, über die Indizes zu iterieren:

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

Aber das erscheint mir etwas unpythonisch. Gibt es einen besseren Weg?

Lösung

Python 3

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

zip hört auf, wenn die kürzere der beiden Varianten foo oder bar aufhört.

In Python 3 gibt zip einen Iterator von Tupeln zurück, wie itertools.izip in Python2. Um eine Liste von Tupeln zu erhalten, verwenden Sie list(zip(foo, bar)). Und um zu zippen, bis beide Iteratoren erschöpft sind erschöpft sind, würden Sie verwenden itertools.zip_longest.

Python 2

In Python 2 gibt zip eine Liste von Tupeln zurück. Das ist in Ordnung, wenn foo und bar nicht massiv sind. Wenn sie beide massiv sind, dann ist die Bildung von zip(foo,bar) eine unnötig massive temporäre Variable und sollte ersetzt werden durch itertools.izip oder itertools.izip_longest ersetzt werden, das einen Iterator statt 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)

izip hält an, wenn entweder foo oder bar erschöpft ist. izip_longest hört auf, wenn sowohl foo als auch bar erschöpft sind. Wenn der/die kürzere(n) Iterator(en) erschöpft sind, liefert izip_longest ein Tupel mit None an der Position, die diesem Iterator entspricht. Sie können auch einen anderen Füllwert als None setzen, wenn Sie wollen. Siehe hier für die vollständige Geschichte.


Beachten Sie auch, dass zip und seine zip-ähnlichen Abkömmlinge eine beliebige Anzahl von Iterablen als Argumente akzeptieren können. 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
Kommentare (9)

Sie benötigen die Funktion zip.

for (f,b) in zip(foo, bar):
    print "f: ", f ,"; b: ", b
Kommentare (1)

Sie sollten die Funktion 'zip' 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)
Kommentare (2)