← Все вопросы

Как перебрать два списка одновременно в Python (zip)?

Задан 4 месяца назад815 просмотров2 ответа
8

У меня два списка одинаковой длины — имена и оценки. Хочу пройти их в одном цикле, чтобы на каждом шаге был и элемент из первого, и из второго. Сейчас бегаю по индексам через range(len()), но выглядит громоздко. Как итерировать два списка параллельно?

2 ответа

13
✓ Принятый ответ — помог автору

Идеальный инструмент — zip. Он спаривает элементы двух (или больше) списков по позициям, и в цикле вы сразу получаете пару:

names = ['Аня', 'Боря', 'Вера']
scores = [5, 4, 3]

for name, score in zip(names, scores):
    print(f'{name}: {score}')
# Аня: 5
# Боря: 4
# Вера: 3

Это чище, чем for i in range(len(names)): с обращениями names[i], scores[i] — меньше шансов перепутать индекс и не нужно следить за длиной.

Списков может быть и больше двух:

for a, b, c in zip(list1, list2, list3):
    ...

Главная ловушка — разная длина. zip молча обрезает по самому короткому списку, без ошибки:

for x, y in zip([1, 2, 3], ['a', 'b']):
    print(x, y)   # только (1,'a') и (2,'b'); тройка потеряна

Если потеря данных недопустима, в Python 3.10+ есть zip(a, b, strict=True) — он бросит ValueError, если длины не совпали. А если, наоборот, нужно дойти до конца длинного списка, подставляя заглушки, берите itertools.zip_longest.

И если нужен ещё индекс — комбинируйте с enumerate: for i, (name, score) in enumerate(zip(names, scores)):.

4

Маленькое дополнение: zip возвращает ленивый итератор, а не список. В цикле это не мешает, но если нужен именно список пар — оберните в list():

pairs = list(zip(names, scores))   # [('Аня', 5), ('Боря', 4), ('Вера', 3)]

И обратная операция — распаковка через zip(*pairs) «разъединяет» пары обратно в два кортежа. Это тот же zip, просто с распаковкой звёздочкой.

Ваш ответ

Войдите, чтобы ответить на вопрос.