Como iterar através de duas listas em paralelo?

865

Eu tenho dois iterables em Python, e quero passar por eles em pares:

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

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

Isso deve resultar em:

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

Uma maneira de fazer isso é iterar sobre os índices:

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

Mas isso me parece um pouco atípico. Tem algum jeito melhor de fazer isso?

Nathan Fellman
fonte

Respostas:

1354

Python 3

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

zippara quando o mais curto fooou barpara.

No Python 3 , zip retorna um iterador de tuplas, como itertools.izipno Python2. Para obter uma lista de tuplas, use list(zip(foo, bar)). E para compactar até que ambos os iteradores estejam esgotados, você usaria itertools.zip_longest .

Python 2

No Python 2 , zip retorna uma lista de tuplas. Isso é bom quando fooe barnão é maciço. Se ambos são maciços, a formação zip(foo,bar)é uma variável temporária desnecessariamente maciça e deve ser substituída por itertools.izipou itertools.izip_longest, que retorna um iterador em vez 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)

izippara quando um fooou barestá esgotado. izip_longestpára quando ambos fooe barestão esgotados. Quando o (s) iterador (es) mais curto (s) estão esgotados, izip_longestproduz uma tupla Nonena posição correspondente a esse iterador. Você também pode definir uma diferente fillvaluealém de Nonese desejar. Veja aqui a história completa .


Observe também que zipe seus zipirmãos semelhantes podem aceitar um número arbitrário de iteráveis ​​como argumentos. Por exemplo,

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

impressões

1 red manchego
2 blue stilton
3 green brie
unutbu
fonte
@unutbu Por que eu preferiria o método OP ao invés do método izip(mesmo que o izip/ zippareça muito mais limpo)?
Armundle # 14/16
3
Você pode mencionar o Python 3 primeiro, pois provavelmente é mais à prova de futuro. Além disso, vale ressaltar que no Python 3, zip () tem exatamente a vantagem que somente itertools.izip () tinha no Python 2 e, portanto, geralmente é o caminho a seguir.
Daniel S.
3
Posso pedir que você atualize sua resposta para declarar explicitamente que funções like zipe ziplike itertoolsaceitam qualquer número de iterables e não apenas 2? Esta pergunta é canônica agora e sua resposta é a única que vale a pena atualizar.
vaultah
e se, além disso, eu quiser o índice i? Posso agrupar esse zip em enumerar?
Charlie Parker
2
@CharlieParker: Sim, você pode, mas então você usaria for i, (f, b) in enumerate(zip(foo, bar)).
Unutbu 6/0318
60

Você quer a zipfunção.

for (f,b) in zip(foo, bar):
    print "f: ", f ,"; b: ", b
Karl Guertin
fonte
11
Antes do Python 3.0, você gostaria de usar itertools.izipse tiver um grande número de elementos.
Georg Schölly 02/11/2009
15

Você deve usar a função ' zip '. Aqui está um exemplo de como sua própria função zip pode parecer

def custom_zip(seq1, seq2):
    it1 = iter(seq1)
    it2 = iter(seq2)
    while True:
        yield next(it1), next(it2)
Vlad Bezden
fonte
Isso não tem exatamente o mesmo resultado que zip(seq1, seq2)?
Niklas Mertsch 06/06/19
@NiklasMertsch sim, tem exatamente o mesmo resultado. Eu só forneceu exemplo, como zip função é semelhante
Vlad Bezden
0

Você pode agrupar os enésimos elementos em uma tupla ou lista usando compreensão e distribuí-los com uma função geradora.

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
fonte
-2

Caso alguém esteja procurando algo assim, achei muito simples e fácil:

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

As listas serão iteradas com seu conteúdo completo, diferentemente do zip (), que itera apenas até o tamanho mínimo do conteúdo.

VladiC4T
fonte
downvoters devem comentar o que acharam errado com minha abordagem ou se ela não se encaixa como uma possível solução para essa pergunta.
VladiC4T 21/04