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


861

У мене є два ітерабелі в 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]

Але це здається мені дещо нетиповим. Чи є кращий спосіб це зробити?

Відповіді:


1349

Пітон 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_lo most .

Пітон 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 Чому я віддаю перевагу методу ОП над методом 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 так, це точно такий же результат. Я щойно
наводив

0

Ви можете зв’язати 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 (), який ітераціює лише до мінімальної довжини вмісту.


downvoters повинні прокоментувати те, що вони виявили не так у моєму підході, або якщо це не відповідає як можливе рішення цього питання.
VladiC4T

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.