Ik heb twee iterabelen in Python, en ik wil ze per twee overlopen:
foo = (1, 2, 3)
bar = (4, 5, 6)
for (f, b) in some_iterator(foo, bar):
print "f: ", f, "; b: ", b
Het zou moeten resulteren in:
f: 1; b: 4
f: 2; b: 5
f: 3; b: 6
Eén manier om het te doen is om over de indexen te itereren:
for i in xrange(len(foo)):
print "f: ", foo[i], "; b: ", b[i]
Maar dat lijkt me wat onpythonisch. Is er een betere manier om het te doen?
for f, b in zip(foo, bar):
print(f, b)
zip
stopt als de kortere van foo
of bar
stopt.
In Python 3, zip
een iterator van tupels, zoals itertools.izip
in Python2. Om een lijst
van tupels te krijgen, gebruik je list(zip(foo, bar))
. En om te zippen totdat beide iterators
uitgeput zijn, zou je gebruik maken van
itertools.zip_longest.
In Python 2, zip
een lijst van tupels terug. Dit is prima als foo
en bar
niet massief zijn. Als ze beide massief zijn, dan is het vormen van zip(foo,bar)
een onnodig massieve
tijdelijke variabele, en moet worden vervangen door itertools.izip
of
itertools.izip_longest
, die een iterator teruggeeft in plaats van een lijst.
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
stopt als foo
of bar
is uitgeput.
izip_longest
stopt als zowel foo
als bar
uitgeput zijn.
Als de kortere iterator(en) uitgeput zijn, geeft izip_longest
een tupel met None
op de positie die overeenkomt met die iterator. Je kunt ook een andere fillvalue
dan None
instellen als je dat wilt. Zie hier voor het volledige verhaal.
Merk ook op dat zip
en zijn zip
-achtige brethen een willekeurig aantal iterables als argumenten kunnen accepteren. Bijvoorbeeld,
for num, cheese, color in zip([1,2,3], ['manchego', 'stilton', 'brie'],
['red', 'blue', 'green']):
print('{} {} {}'.format(num, color, cheese))
drukt
1 red manchego
2 blue stilton
3 green brie