Объединение и распаковка последовательностей с помощью zip() и itertools.zip_longest()

Опубликован: 18.08.2023 104

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

Функция zip() принимает на вход несколько объектов-аргументов и создаёт из них итератор кортежей (zip-объект), в котором:

  • первый элемент содержит кортеж из первых элементов всех объектов-аргументов;
  • второй элемент соответственно - кортеж из вторых элементов;
  • и так далее.

Ниже приведен пример объединения с помощью функции zip() трех итерируемых последовательностей (списка и двух кортежей):

s = 'ABC'
t = (10, 20, 30)
u = (-5, -10, -15)

list(zip(s, t, u))
[('A', 10, -5), ('B', 20, -10), ('C', 30, -15)]

Если в функцию zip() передать объекты разной длины, то функция выдаст результирующий zip-объект, длина которого будет равна самому короткому входному объекту:

s = 'ABC'
t = (10, 20, 30, 40, 50)

print(list(zip(s, t)))
[('A', 10), ('B', 20), ('C', 30)]

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

Синтаксис: itertools.zip_longest(*iterables, fillvalue=None)

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

import itertools

print(list(itertools.zip_longest(range(10), 'ABCDE')))
[(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D'), (4, 'E'), (5, None), (6, None), (7, None), (8, None), (9, None)]

for (i, j) in itertools.zip_longest(range(10), 'ABCDE', fillvalue='-->'):
    print(i, j)
0 A
1 B
2 C
3 D
4 E
5 -->
6 -->
7 -->
8 -->
9 -->

Примеры применения фукции zip()

# параллельный обход списков в циклах for
letters = ['a', 'b', 'c']
numbers = [0, 1, 2]
operators = ['*', '/', '+']

for l, n, o in zip(letters, numbers, operators):
    print(f'Letter: {l}')
    print(f'Number: {n}')
    print(f'Operator: {o}')

Letter: a
Number: 0
Operator: *
Letter: b
Number: 1
Operator: /
Letter: c
Number: 2
Operator: +

# создание словарей
names = ['Tom', 'Dick', 'Harry']
ages = [50, 35, 60]

dict(zip(names, ages))
{'Harry': 60, 'Dick': 35, 'Tom': 50}

# параллельная обработка словарей
dict_one = {'name': 'John', 'last_name': 'Doe', 'job': 'Python Consultant'}
dict_two = {'name': 'Jane', 'last_name': 'Doe', 'job': 'Community Manager'}

for (k1, v1), (k2, v2) in zip(dict_one.items(), dict_two.items()):
    print(k1, '->', v1)
    print(k2, '->', v2)

name -> John
name -> Jane
last_name -> Doe
last_name -> Doe
job -> Python Consultant
job -> Community Manager

Распаковка с помощью zip() и оператора распаковки *.

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

Приведенный ниже пример показывает способ распаковки списка кортежей с разделением элементов каждого кортежа на независимые последовательности.

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

Похожие посты

Фильтрация элементов итератора с помощью bool-списка функции itertools.compress()

Пропуск не нужных элементов последовательности с помощью itertools.dropwhile()

Возвращение элементов списка пока условие истинно с помощью itertools.takewhile()

Бесконечные итераторы в Python itertools.count(), cycle(), repeat()

Комментариев нет.