Come scorrere due elenchi in parallelo?


865

Ho due iterabili in Python e voglio superarli in coppia:

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

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

Dovrebbe comportare:

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

Un modo per farlo è iterare sugli indici:

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

Ma questo mi sembra in qualche modo poco realistico. C'è un modo migliore per farlo?

Risposte:


1354

Python 3

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

zipsi interrompe quando il più breve fooo si barferma.

In Python 3 , zip restituisce un iteratore di tuple, come itertools.izipin Python2. Per ottenere un elenco di tuple, utilizzare list(zip(foo, bar)). E per comprimere fino a quando entrambi gli iteratori sono esauriti, dovresti usare itertools.zip_longest .

Python 2

In Python 2 , zip restituisce un elenco di tuple. Questo va bene quando fooe barnon sono enormi. Se sono entrambi massicci, la formazione zip(foo,bar)è una variabile temporanea inutilmente massiccia e deve essere sostituita da itertools.izipo itertools.izip_longest, che restituisce un iteratore anziché un elenco.

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)

izipsi ferma quando uno fooo barè esaurito. izip_longestsi ferma quando entrambi fooe barsono esauriti. Quando gli iteratori più corti sono esauriti, izip_longestproduce una tupla con Nonenella posizione corrispondente a quell'iteratore. È anche possibile impostare un diverso fillvalueoltre Nonese lo si desidera. Vedi qui per la storia completa .


Si noti inoltre che zipe il suo zipsimile brethen può 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))

stampe

1 red manchego
2 blue stilton
3 green brie

@unutbu Perché dovrei preferire il metodo OP rispetto a izipquello (anche se il izip/ zipsembra molto più pulito)?
armundle

3
Potresti voler prima menzionare Python 3, poiché è probabilmente più a prova di futuro. Inoltre, vale la pena sottolineare che in Python 3, zip () ha esattamente quel vantaggio che solo itertools.izip () aveva in Python 2 e quindi di solito è la strada da percorrere.
Daniel S.

3
Posso chiederle di aggiornare la risposta a esplicitamente che zipe zip-come funzioni da itertoolsaccettare qualsiasi numero di iterables e non solo 2? Questa domanda è canonica ora e la tua risposta è l'unica degna di essere aggiornata.
vaultah,

cosa succede se in più desidero l'indice i? Posso racchiudere quella zip in un elenco?
Charlie Parker,

2
@CharlieParker: Sì, puoi, ma poi useresti for i, (f, b) in enumerate(zip(foo, bar)).
unutbu,

60

Vuoi la zipfunzione.

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

11
Prima di Python 3.0 dovresti usarlo itertools.izipse hai un gran numero di elementi.
Georg Schölly,

15

Dovresti usare la funzione ' zip '. Ecco un esempio di come può apparire la tua funzione zip

def custom_zip(seq1, seq2):
    it1 = iter(seq1)
    it2 = iter(seq2)
    while True:
        yield next(it1), next(it2)

Questo non ha esattamente lo stesso risultato di zip(seq1, seq2)?
Niklas Mertsch,

@NiklasMertsch sì, ha esattamente lo stesso risultato. Ho appena fornito un esempio di come appare la funzione zip
Vlad Bezden,

1

Puoi raggruppare gli ennesimi elementi in una tupla o in un elenco usando la comprensione, quindi distribuirli con una funzione di generatore.

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))

-2

Nel caso in cui qualcuno stia cercando qualcosa di simile, l'ho trovato molto semplice e facile:

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

Gli elenchi verranno ripetuti con il loro contenuto completo, a differenza di zip () che scorre solo fino alla lunghezza minima del contenuto.


i downvoter dovrebbero commentare ciò che hanno trovato sbagliato nel mio approccio o se non si adatta come possibile soluzione a questa domanda.
VladiC4T,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.