Eu tenho dois iterables em Python, e quero passá-los aos pares:
foo = (1, 2, 3)
bar = (4, 5, 6)
for (f, b) in some_iterator(foo, bar):
print "f: ", f, "; b: ", b
Deve resultar em:
f: 1; b: 4
f: 2; b: 5
f: 3; b: 6
Uma maneira de o fazer é iterar sobre os índices:
for i in xrange(len(foo)):
print "f: ", foo[i], "; b: ", b[i]
Mas isso parece-me um pouco antipietico. Há uma maneira melhor de o fazer?
for f, b in zip(foo, bar):
print(f, b)
O "zip" pára quando o mais curto de "foo" ou "bar" pára.
Em **Python 3***, zip
retorna um iterador de tuplos, como itertools.izip
em Python2. Para obter uma lista
de tuplos, utilize list(zip(foo, bar))
. E para zipar até que ambos os iteradores estejam
exausto, você usaria
itertools.zip_longest.
Em **Python 2***, zip
devolve uma lista de tuplos. Isto é bom quando foo
e bar
não são massivos. Se ambos são massivos, então formar zip(foo,bar)
é desnecessariamente massivo.
variável temporária, e deve ser substituída por itertools.izip
ou
itertools.izip_longest', que retorna um iterador ao invés de uma 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)
O izip
pára quando o foo
ou o bar
se esgota.
O izip_longest
pára quando tanto o foo
como o bar
estão exaustos.
Quando o(s) iterador(es) mais curto(s) se esgotam, izip_longest
produz um tuple com None
na posição correspondente a esse iterador. Você também pode definir outro fillvalue
além de None
se você desejar. Veja aqui para a história completa.
Note também que o zip' e suas cervejas tipo
zip' podem aceitar um número arbitrário de iterables como argumentos. Por exemplo,
for num, cheese, color in zip([1,2,3], ['manchego', 'stilton', 'brie'],
['red', 'blue', 'green']):
print('{} {} {}'.format(num, color, cheese))
estampas
1 red manchego
2 blue stilton
3 green brie