Объединение итерируемых объектов с помощью zip

Раздел: Стандартная библиотека Python -> Архивация и упаковка данных

Функция zip: основы и варианты использования

Как выполнить параллельную итерацию по нескольким коллекциям?

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


names = ['Анна', 'Борис', 'Виктор']
scores = [85, 92, 78]
for name, score in zip(names, scores):
    print(f'{name}: {score}')

Python zip (функция zip в python)

Анна: 85
Борис: 92
Виктор: 78

Такой подход удобен для обработки связанных данных, хранящихся в отдельных списках.

Типичная ошибка: если списки имеют разную длину, zip молча обрежет результат до наименьшей длины. Это может привести к потере данных. Выход: использовать itertools.zip_longest (см. один из вариантов ниже).

Как создать словарь из двух списков ключей и значений?

Функция dict(zip(keys, values)) позволяет объединить два списка в словарь. Каждый элемент первого списка становится ключом, а элемент второго списка становится значением.


keys = ['a', 'b', 'c']
values = [1, 2, 3]
result = dict(zip(keys, values))
print(result)
{'a': 1, 'b': 2, 'c': 3}

Этот приём часто применяется при обработке данных из CSV или конфигурационных файлов, где заголовки и строки хранятся отдельно.

Проблема: если списки разной длины, лишние ключи или значения будут отброшены. Для обеспечения полного соответствия следует предварительно выровнять длины с помощью itertools.zip_longest.

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

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


pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
numbers, letters = zip(*pairs)
print(list(numbers), list(letters))
[1, 2, 3] ['a', 'b', 'c']

Такой способ удобен для транспонирования матриц, представленных в виде списка строк.

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

Как обработать итерации разной длины без потери элементов?

Модуль itertools предоставляет функцию zip_longest, которая продолжает итерацию до исчерпания самого длинного аргумента, заполняя отсутствующие значения указанным fillvalue (по умолчанию None).


from itertools import zip_longest

a = [1, 2, 3]
b = ['x', 'y']
for num, char in zip_longest(a, b, fillvalue='?'):
    print(f'{num} -> {char}')
1 -> x
2 -> y
3 -> ?

Это необходимо при работе с данными, где не гарантируется одинаковая длина столбцов, например, при слиянии выборок разного объёма.

Внимание: при наличии большого количества заполнителей может возникнуть неоднозначность, если fillvalue совпадет с реальными данными. Следует выбирать уникальное значение (например, object()).

Как получить индексы элементов при параллельной итерации?

Комбинирование enumerate и zip позволяет одновременно получать порядковый номер и соответствующие элементы нескольких коллекций.


colors = ['red', 'green', 'blue']
codes = ['FF0000', '00FF00', '0000FF']
for i, (color, code) in enumerate(zip(colors, codes), start=1):
    print(f'{i}. {color} -> {code}')
1. red -> FF0000
2. green -> 00FF00
3. blue -> 0000FF

Этот приём полезен при выводе нумерованных списков или при обработке данных, где важен порядок.

Нюанс: при большом количестве списков конструкция for i, (a, b, c) in enumerate(zip(...)) может стать громоздкой. В таких случаях лучше вынести распаковку в отдельные переменные.

Расширенные примеры использования функции zip

Пример 1: Транспонирование матрицы (список строк).

Пример

matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]
transposed = list(zip(*matrix))
print(transposed)
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]

Здесь оператор распаковки *matrix передаёт каждую строку как отдельный аргумент. zip собирает первые элементы каждой строки, вторые и т.д. В результате получаются кортежи, представляющие столбцы исходной матрицы.

Пример 2: Создание списка кортежей с явным преобразованием в список.

Пример

list(zip([1, 2], ['a', 'b'], [True, False]))
[(1, 'a', True), (2, 'b', False)]

По умолчанию zip возвращает итератор. Обёртка в list() материализует все кортежи.

Пример 3: Использование zip с генераторами (ленивые вычисления).

Пример

def gen1():
    yield from range(5)
def gen2():
    yield from 'abcde'
pairs = zip(gen1(), gen2())
for p in pairs:
    print(p)
(0, 'a')
(1, 'b')
(2, 'c')
(3, 'd')
(4, 'e')

Генераторы вычисляются на лету, что экономит память.

Пример 4: zip с itertools.cycle для создания пар с повторением.

Пример

from itertools import cycle
numbers = [1, 2, 3, 4]
letters = cycle(['a', 'b'])
pairs = list(zip(numbers, letters))
print(pairs)
[(1, 'a'), (2, 'b'), (3, 'a'), (4, 'b')]

Циклический итератор автоматически повторяет короткий список.

Пример 5: zip_longest с разными типами заполнителя.

Пример

from itertools import zip_longest
a = [1, 2]
b = [10, 20, 30]
c = [100]
result = list(zip_longest(a, b, c, fillvalue=0))
print(result)
[(1, 10, 100), (2, 20, 0), (0, 30, 0)]

Отсутствующие элементы заменяются нулём.

Пример 6: Параллельное чтение двух файлов.

Пример

with open('file1.txt') as f1, open('file2.txt') as f2:
    for line1, line2 in zip(f1, f2):
        print(f'{line1.strip()} | {line2.strip()}')
строка1 | lineA
строка2 | lineB

Обратите внимание: если файлы разной длины, zip остановится на меньшем.

Пример 7: Распаковка кортежа с переменным числом элементов (head, *tail).

Пример

pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
first, *rest = zip(*pairs)
print(first)
print(rest)
(1, 2, 3)
[('a', 'b', 'c')]

Пример 8: Использование zip для сортировки нескольких списков параллельно.

Пример

names = ['C', 'A', 'B']
ages = [30, 20, 25]
sorted_pairs = sorted(zip(names, ages))
sorted_names, sorted_ages = zip(*sorted_pairs)
print(list(sorted_names), list(sorted_ages))
['A', 'B', 'C'] [20, 25, 30]

Сначала создаются пары, затем сортируются по первому элементу (имени). Распаковка возвращает отсортированные списки.

функция zip в Python - comments

En
Python zip (python)