Как перебирать два списка параллельно?

865

У меня есть две итерации в Python, и я хочу просмотреть их попарно:

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

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

Это должно привести к:

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

Один из способов сделать это - перебрать индексы:

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

Но это кажется мне несколько нелепым. Есть ли лучший способ сделать это?

Натан Феллман
источник

Ответы:

1354

Python 3

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

zipостанавливается, когда короче fooили barостанавливается.

В Python 3 , zip возвращает итератор кортежей, как itertools.izipв python2. Чтобы получить список кортежей, используйте list(zip(foo, bar)). И чтобы архивировать до тех пор, пока оба итератора не будут исчерпаны, вы должны использовать itertools.zip_longest .

Python 2

В Python 2 , zip возвращает список кортежей. Это хорошо, когда fooи barне массивные. Если они оба являются массивными, то формирование zip(foo,bar)является излишне массивной временной переменной и должно быть заменено на itertools.izipили itertools.izip_longest, которое возвращает итератор вместо списка.

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останавливается , когда либо fooили barистощается. izip_longestостанавливается, когда оба fooи barисчерпаны. Когда более короткие итераторы будут исчерпаны, izip_longestвыдается кортеж с Noneпозицией, соответствующей этому итератору. Вы также можете установить другое, fillvalueкроме того, Noneесли вы хотите. Смотрите здесь для полной истории .


Также обратите внимание, что zipи zipподобные ему элементы могут принимать произвольное число итераций в качестве аргументов. Например,

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

печать

1 red manchego
2 blue stilton
3 green brie
unutbu
источник
@unutbu Почему я предпочел бы метод OP, а не метод izip(хотя izip/ zipвыглядит намного чище)?
armundle
3
Возможно, вы захотите сначала упомянуть Python 3, так как он, вероятно, более перспективен на будущее. Более того, стоит отметить, что в Python 3 у zip () есть именно то преимущество, которое было только у itertools.izip () в Python 2, и, таким образом, это, как правило, путь.
Даниэль С.
3
Могу ли я попросить вас обновить ваш ответ, чтобы явно указать, что zipи zip-подобные функции могут itertoolsпринимать любое количество повторений, а не только 2? Этот вопрос сейчас каноничен, и ваш ответ - единственный, который стоит обновить.
vaultah
что если дополнительно я хочу индекс i? Могу ли я обернуть этот почтовый индекс в перечислять?
Чарли Паркер
2
@CharlieParker: Да, вы можете, но тогда вы бы использовали for i, (f, b) in enumerate(zip(foo, bar)).
unutbu
60

Вы хотите zipфункцию.

for (f,b) in zip(foo, bar):
    print "f: ", f ,"; b: ", b
Карл Гертин
источник
11
До Python 3.0 вы хотели бы использовать, itertools.izipесли у вас есть большое количество элементов.
Георг Шолли
15

Вы должны использовать функцию « zip ». Вот пример того, как может выглядеть ваша собственная функция zip

def custom_zip(seq1, seq2):
    it1 = iter(seq1)
    it2 = iter(seq2)
    while True:
        yield next(it1), next(it2)
Влад Безден
источник
Разве это не имеет точно такой же результат, как zip(seq1, seq2)?
Никлас Мерч
@NiklasMertsch да, это точно такой же результат. Я только что привел пример того, как выглядит функция zip
Влад Безден,
1

Вы можете связать n-е элементы в кортеж или список, используя понимание, а затем передать их с помощью функции генератора.

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

В случае, если кто-то ищет что-то подобное, я нахожу это очень простым и легким:

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

Списки будут повторяться со своим полным содержимым, в отличие от zip (), который повторяет только до минимальной длины содержимого.

VladiC4T
источник
downvoters должны прокомментировать, что они нашли неправильно с моим подходом или если он не подходит в качестве возможного решения этого вопроса.
VladiC4T