Сообщить об ошибке.

Функция zip() в Python, объединить элементы в список кортежей.

Объединяет элементы последовательностей в список кортежей.

Синтаксис:

zip(*iterables)

Параметры:

Возвращаемое значение:

Описание:

Функция zip() создает итератор кортежей, который объединяет элементы каждой из переданных последовательностей *iterables.

Функцию zip() возвращает итератор кортежей, где i-й кортеж содержит i-й элемент из каждой последовательности аргументов или итераций. Итератор останавливается, когда самая короткая входная итерация заканчивается. С единственным итерируемым аргументом, он возвращает итератор из 1 кортежа. Без аргументов возвращает пустой итератор.

Функция zip() эквивалентна следующему коду:

def zip(*iterables):
    # zip('ABCD', 'xy') --> Ax By
    sentinel = object()
    iterators = [iter(it) for it in iterables]
    while iterators:
        result = []
        for it in iterators:
            elem = next(it, sentinel)
            if elem is sentinel:
                return
            result.append(elem)
        yield tuple(result)

Функцию zip() следует использовать с последовательностями неравной длины, если вам не нужны конечные, не сопоставимые значения из более длинных итераций. Если эти значения важны, используйте itertools.zip_longest().

Примеры объединения элементов нескольких списков в список кортежей:

# если передать один оргумент
>>> a = [1, 2, 3, 4, 5, 6]
>>> x = zip(a)
>>> list(x)
# [(1,), (2,), (3,), (4,), (5,), (6,)]

# передаем два аргумента
>>> a = range(5)
>>> b = range(5, 10)
>>> x = zip(a, b)
>>> list(x)
# [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)]

# Один список меньше другого
a = [1, 2, 3, 4, 5, 6]
b = ['a', 'b', 'c', 'd']
c = range(5, 10)
# функция `zip()` объединит последовательности до самой
# короткой из них, остальные элементы будут отброшены
x = zip(a, b, c)
list(x)
# [(1, 'a', 5), (2, 'b', 6), (3, 'c', 7), (4, 'd', 8)]

Как и где можно использовать функцию zip()

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

Совместно с оператором распаковки * в аргументах функции zip() можно использовать распаковку списка кортежей на отдельные списки:

>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
# объединим два списка 
>>> zipped = zip(x, y)
>>> list(zipped)
# [(1, 4), (2, 5), (3, 6)]

# распакуем полученный список кортежей
>>> x2, y2 = zip(*zipped)
# сравниваем полученные списки
# с их исходными значениями
>>> list(x2) == x and list(y2) == y
# True

Сортировка нескольких связанных между собой списков.

Допустим, что есть несколько списков, которые связаны между собой по индексам и их нужно отсортировать, при этом не нарушив связей.

Рассмотрим такую ситуацию на примере из трех связанных списка, в этом случае связь означает, что нулевой элемент первого списка связан с нулевым элементом второго списка, и с нулевым элементом третьего списка, далее первый элемент первого списка связан с первым элементом второго списка, и с первым элементом третьего списка и т.д.

Следовательно сортировать списки по отдельности нельзя, т.к. нарушиться связь. Смотрим как можно сортировать такие списки, используя функцию zip()

>>> from random import shuffle
# приготовим первый список
>>> x = list(range(6))
# перемешаем его
>>> shuffle(x)
# приготовим второй список
>>> y = list(range(6))
# третий список пусть будет перевернутый `y` 
>>> z = list(reversed(y))
# распечатаем для наглядности
>>> print(f'x: {x}\ny: {y}\nz: {z}')
# x: [3, 5, 2, 1, 4, 0], 
# y: [0, 1, 2, 3, 4, 5], 
# z: [5, 4, 3, 2, 1, 0])

# сортируем по первому списку `x`
>>> x, y, z = zip(*sorted(zip(x, y, z), key=lambda tpl: tpl[0]))
>>> print(f'{list(x)}\n{list(y)}\n{list(z)}')
# [0, 1, 2, 3, 4, 5]
# [5, 3, 2, 0, 4, 1]
# [0, 2, 3, 5, 1, 4]

# теперь сортируем по последнему списку `z`
# обратите внимание, что меняется только 
# аргумент `key` в функции `sorted()`
>>> x, y, z = zip(*sorted(zip(x, y, z), key=lambda tpl: tpl[2]))
>>> print(f'{list(x)}\n{list(y)}\n{list(z)}')
# [0, 4, 1, 2, 5, 3]
# [5, 4, 3, 2, 1, 0]
# [0, 1, 2, 3, 4, 5]

Функция zip() в циклах for/in.

Есть такие ситуации, когда необходимо перебрать несколько списков в одном цикле for/in. Первое, что приходит в голову, это вытаскивать элементы этих списков в цикле по индексу, как то так:

for i in range(len(list1))
    a, b, c = list1[i], list2[i], list3[i]

# или

for i, a in enumerate(list1)
    b, c = list2[i], list3[i]

Но есть способ проще и эффектнее с использованием функции zip():

>>> lst1 = [0, 1, 2, 3, 4, 5]
>>> lst2 = [5, 3, 2, 0, 4, 1]
>>> lst3 = ['zero', 'one', 'two', 'three', 'four', 'five']
>>> for a, b, c in zip(lst1, lst2, lst3):
...     print(f'{c}:\t{a} + {b} = {a + b}')
...
# zero:   0 + 5 = 5
# one:    1 + 3 = 4
# two:    2 + 2 = 4
# three:  3 + 0 = 3
# four:   4 + 4 = 8
# five:   5 + 1 = 6

Создание словаря из двух списков.

>>> lst1 = [0, 1, 2, 3, 4, 5]
>>> lst2 = ['zero', 'one', 'two', 'three', 'four', 'five']
# создаем словарь при помощи `dict()`
>>> dict(zip(lst1, lst2))
# {0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'}

# создаем словарь при помощи выражения генератора 
# словаря, при этом меняем элементы списков местами
>>> d = {y: x for x, y in zip(lst1, lst2)}
>>> d
# {'zero': 0, 'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5}