Ho due iterabili in Python e voglio esaminarle a coppie:
foo = (1, 2, 3)
bar = (4, 5, 6)
for (f, b) in some_iterator(foo, bar):
print "f: ", f, "; b: ", b
Dovrebbe risultare in:
f: 1; b: 4
f: 2; b: 5
f: 3; b: 6
Un modo per farlo è quello di iterare sugli indici:
for i in xrange(len(foo)):
print "f: ", foo[i], "; b: ", b[i]
Ma questo mi sembra in qualche modo poco sintonico. C'è un modo migliore per farlo?
for f, b in zip(foo, bar):
print(f, b)
zip
si ferma quando il più corto di foo
o bar
si ferma.
In Python 3, zip
restituisce un iteratore di tuple, come itertools.izip
in Python2. Per ottenere una lista
di tuple, usate list(zip(foo, bar))
. E per zippare fino a quando entrambi gli iteratori sono
esauriti, dovreste usare
itertools.zip_longest.
In Python 2, zip
restituisce una lista di tuple. Questo va bene quando foo
e bar
non sono massicce. Se sono entrambi massicci, allora formare zip(foo,bar)
è una variabile temporanea inutilmente massiccia
temporanea, e dovrebbe essere sostituita da itertools.izip
o
itertools.izip_longest
, che restituisce un iteratore invece di una lista.
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
si ferma quando uno dei due foo
o bar
è esaurito.
izip_longest
si ferma quando sia foo
che bar
sono esauriti.
Quando gli iteratori più corti sono esauriti, izip_longest
produce una tupla con None
nella posizione corrispondente a quell'iteratore. Puoi anche impostare un diverso fillvalue
oltre a None
, se vuoi. Vedi qui per la storia completa.
Si noti inoltre che zip
e i suoi fratelli simili a zip
possono accettare un numero arbitrario di iterabili come argomenti. Per esempio,
for num, cheese, color in zip([1,2,3], ['manchego', 'stilton', 'brie'],
['red', 'blue', 'green']):
print('{} {} {}'.format(num, color, cheese))
stampa
1 red manchego
2 blue stilton
3 green brie