Функция zip для прохода по нескольким итерируемым объектам | OTUS

Курсы

Курсы в разработке Подготовительные курсы
Работа в компаниях Компаниям Блог +7 499 110-61-65

Функция zip для прохода по нескольким итерируемым объектам

WebDev_Deep_23.7_site-5020-5557b1.png

Иногда нам нужно пройти по нескольким спискам в одном цикле и взять из них данные с одинаковых позиций. Допустим, у нас есть два списка:

name_hero = [
    'Hulk',
    'Mr. Fantastic',
    'Invisible Woman',
    'Doctor Strange',
    'Doctor Octopus',
    'Spider-Man',
]

name_real = [
    'Bruce Banner',
    'Reed Richards',
    'Sue Storm',
    'Stephen Strange',
    'Otto Octavius',
    'Peter Parker',
]

И перед нами стоит задача обработать пары. К сожалению, в коде новичков часто можно встретить такие подходы:

# Так делать плохо
for i in range(len(name_hero)):
    print(name_hero[i], '-', name_real[i])

# И так делать тоже плохо
for i, nickname in enumerate(name_hero):
    print(nickname, '-', name_real[i])

Такой подход не укладывается в python-way. Поэтому есть встроенный инструмент, чтобы сделать это лучше:

for nickname, name in zip(name_hero, name_real):
    print(nickname, '-', name)

# Все три цикла выведут одинаковый результат:
Hulk - Bruce Banner
Mr. Fantastic - Reed Richards
Invisible Woman - Sue Storm
Doctor Strange - Stephen Strange
Doctor Octopus - Otto Octavius
Spider-Man - Peter Parker

Давайте рассмотрим подробней, что мы получаем, когда используем zip. Так как оттуда возвращается генератор, приведём результат к списку:

names_paired = list(zip(name_hero, name_real))
print(names_paired)

# Результат:
[('Hulk', 'Bruce Banner'), ('Mr. Fantastic', 'Reed Richards'), ('Invisible Woman', 'Sue Storm'), ('Doctor Strange', 'Stephen Strange'), ('Doctor Octopus', 'Otto Octavius'), ('Spider-Man', 'Peter Parker')]

Видим, что мы получили список из тюплов (кортежей), каждый из которых — пара из элементов обоих списков: первый с первым, третий с третьим и т. д., а в цикле мы распаковываем каждую пару в переменные nickname и name.

Однако помимо создания пар zip, поможет также обратно разделить пары на отдельные списки. Для этого передадим туда все пары (распакуем при помощи *):

names_unpaired = list(zip(*names_paired))
print(names_unpaired)

# Получаем список из двух тюплов:
[('Hulk', 'Mr. Fantastic', 'Invisible Woman', 'Doctor Strange', 'Doctor Octopus', 'Spider-Man'), ('Bruce Banner', 'Reed Richards', 'Sue Storm', 'Stephen Strange', 'Otto Octavius', 'Peter Parker')]

# Распаковываем два тюпла
new_name_hero, new_name_real = names_unpaired

# И проверяем, что результаты равны исходным данным
print('name_hero == new_name_hero:', tuple(name_hero) == new_name_hero)
print('name_real == new_name_real:', tuple(name_real) == new_name_real)

# В консоли получаем:
name_hero == new_name_hero: True
name_real == new_name_real: True

Это работает не только с парами, можно использовать необходимое количество аргументов:

first_appeared = [
    'The Incredible Hulk (May 1962)',
    'The Fantastic Four #1 (Nov. 1961)',
    'The Fantastic Four #1 (Nov. 1961)',
    'Strange Tales #110 (July 1963)',
    'The Amazing Spider-Man #3 (July 1963)',
    'Amazing Fantasy #15 (August 1962)',
]


for nickname, name, appeared in zip(name_hero, name_real, first_appeared):
    print(f'{nickname} [{name}]: {appeared}')

Получаем:

Hulk [Bruce Banner]: The Incredible Hulk (May 1962)
Mr. Fantastic [Reed Richards]: The Fantastic Four 1 (Nov. 1961)
Invisible Woman [Sue Storm]: The Fantastic Four 1 (Nov. 1961)
Doctor Strange [Stephen Strange]: Strange Tales 110 (July 1963)
Doctor Octopus [Otto Octavius]: The Amazing Spider-Man 3 (July 1963)
Spider-Man [Peter Parker]: Amazing Fantasy 15 (August 1962)

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться