Встроенные возможности по работе с коллекциями
Мы уже знаем, что для работы с коллекциями в Python есть функции и методы. Однако часто требуется выполнить над коллекциями некоторые операции, которых нет в рассмотренных нами методах и функциях. Тогда на помощь приходят библиотеки (модули).
Библиотека может содержать наборы функций, объединённые по области применения. Например, в данной лекции мы рассмотрим библиотеку для работы с коллекциями. Библиотеки помогают программистам сосредоточиться на решении глобальной задачи, а мелкие, часто возникающие задачи решаются вызовом готовых функций из библиотек.
В Python есть достаточно много стандартных встроенных библиотек. Одной из них является библиотека для работы с коллекциями itertools
. На эту библиотеку оказали влияние такие языки программирования, как APL, Haskell и SML.
Чтобы получить доступ к функциям библиотеки, её необходимо подключить к своей программе (импортировать). Это можно сделать, используя ключевое слово import
вместе с названием библиотеки. Импорт библиотек осуществляется в начале программы. После секции импорта следует оставить одну пустую строку по стандарту PEP 8. Пример импорта библиотеки itertools
:
import itertools
Если теперь нам потребуется в этой библиотеке какая-то функция, например product()
, то для её вызова нужно написать название библиотеки, поставить точку и написать название функции:
import itertools
print(itertools.product("ABC", repeat=2))
Как видим из программы, для доступа к функциям библиотеки мы обращаемся сначала к самой библиотеке, а потом уже вызываем из неё функцию.
Можно импортировать функции из библиотек так, как если бы они стали частью нашей программы. Тогда следует указать ключевое слово from
, затем название библиотеки, а после — import
и через запятую указать названия функций, которые будут импортированы в нашу программу. При таком импорте вызов функций библиотеки осуществляется без указания названия библиотеки:
from itertools import product
print(product("ABC", repeat=2))
Обратите внимание: функции библиотеки itertools
возвращают не список, а итератор. Он не хранит все значения сразу, а позволяет один раз последовательно пройти по ним в цикле.
Для сохранения всех значений итератора его можно преобразовать в список с помощью функции list()
.
Рассмотрим некоторые полезные функции библиотеки itertools
.
Функции библиотеки itertools
можно разделить на следующие группы:
- Функции, возвращающие бесконечные итераторы
Эти функции позволяют создавать из конечных коллекций бесконечные итераторы, то есть их элементы можно перебирать в бесконечном цикле.
count(start, step)
— принимает на вход начальное значение (start
, по умолчанию равно 0) и шаг (step
, по умолчанию равен 1) бесконечно увеличивающейся числовой последовательности. В качестве значений аргументов можно использовать вещественные числа (float
). Затем функция возвращает итератор, значения которого являются выходной последовательностью. Выведем числа от 0 до 1 с шагом 0.1. Так как возвращаемый итератор бесконечный, применим break
для остановки цикла:
from itertools import count
for value in count(0, 0.1):
if value <= 1:
print(round(value, 1))
else:
break
Вывод программы:
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
cycle(iterable)
— принимает на вход итерируемый объект, а возвращает итератор, который бесконечно циклически перебирает значения коллекции. Напишем программу, которая выводит строку длиной 10 символов, циклически перебирая символы входной строки ABC
:
from itertools import cycle
max_len = 10
s = ""
for letter in cycle("ABC"):
if len(s) < max_len:
s += letter
else:
break
print(s)
Вывод программы:
ABCABCABCA
repeat(object, times)
— возвращает итератор, повторяющий значение object
(по умолчанию бесконечное количество раз — либо равно значению times
). Напишем программу, которая создаст список из пяти строк ABC
и выведет его на экран:
from itertools import repeat
result = list(repeat("ABC", 5))
print(result)
Вывод программы:
['ABC', 'ABC', 'ABC', 'ABC', 'ABC']
- Функции, выполняющиеся до кратчайшей входной последовательности
accumulate(iterable)
— возвращает итератор, состоящий из накопленных сумм элементов входной последовательности. Например,
from itertools import accumulate
for value in accumulate([1, 2, 3, 4, 5]):
print(value)
Вывод программы:
1 3 6 10 15
chain(i_1, i_2, ..., i_n)
— возвращает итератор, состоящий из элементов первого итерируемого объекта i_1, затем из второго i_2 и так далее до i_n. Пример:
from itertools import chain
values = list(chain("АБВ", "ГДЕЁ", "ЖЗИЙК"))
print(values)
Вывод программы:
['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К']
chain.from_iterable(iterable)
— аналогична chain
, но аргументом является один итерируемый объект, состоящий из итерируемых элементов. Пример:
from itertools import chain
values = list(chain.from_iterable(["АБВ", "ГДЕЁ", "ЖЗИЙК"]))
print(values)
Вывод программы:
['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К']
- Функции для комбинаторики
product(i_1, i_2, ..., i_n, repeat)
— возвращает итератор, значениями которого выступают элементы декартова произведения итерируемых объектов i_1, i_2, ..., i_n. Аргумент repeat
определяет, сколько раз повторять в выходных комбинациях элементы каждого итерируемого объекта (значение по умолчанию 1). Элементами полученного итератора будут все возможные упорядоченные наборы элементов исходных итерируемых объектов. Пример:
from itertools import product
values = list(product([1, 2, 3], "АБВГ"))
print(values)
Вывод программы:
[(1, 'А'), (1, 'Б'), (1, 'В'), (1, 'Г'), (2, 'А'), (2, 'Б'), (2, 'В'), (2, 'Г'), (3, 'А'), (3, 'Б'), (3, 'В'), (3, 'Г')]
Тот же пример, но со значением repeat=2:
from itertools import product
values = list(product([1, 2, 3], "АБВГ", repeat=2))
print(values)
Вывод программы:
[(1, 'А', 1, 'А'), (1, 'А', 1, 'Б'), (1, 'А', 1, 'В'), (1, 'А', 1, 'Г'), (1, 'А', 2, 'А'), (1, 'А', 2, 'Б'), (1, 'А', 2, 'В'), (1, 'А', 2, 'Г'), (1, 'А', 3, 'А'), (1, 'А', 3, 'Б'), (1, 'А', 3, 'В'), (1, 'А', 3, 'Г'), (1, 'Б', 1, 'А'), (1, 'Б', 1, 'Б'), (1, 'Б', 1, 'В'), (1, 'Б', 1, 'Г'), (1, 'Б', 2, 'А'), (1, 'Б', 2, 'Б'), (1, 'Б', 2, 'В'), (1, 'Б', 2, 'Г'), (1, 'Б', 3, 'А'), (1, 'Б', 3, 'Б'), (1, 'Б', 3, 'В'), (1, 'Б', 3, 'Г'), (1, 'В', 1, 'А'), (1, 'В', 1, 'Б'), (1, 'В', 1, 'В'), (1, 'В', 1, 'Г'), (1, 'В', 2, 'А'), (1, 'В', 2, 'Б'), (1, 'В', 2, 'В'), (1, 'В', 2, 'Г'), (1, 'В', 3, 'А'), (1, 'В', 3, 'Б'), (1, 'В', 3, 'В'), (1, 'В', 3, 'Г'), (1, 'Г', 1, 'А'), (1, 'Г', 1, 'Б'), (1, 'Г', 1, 'В'), (1, 'Г', 1, 'Г'), (1, 'Г', 2, 'А'), (1, 'Г', 2, 'Б'), (1, 'Г', 2, 'В'), (1, 'Г', 2, 'Г'), (1, 'Г', 3, 'А'), (1, 'Г', 3, 'Б'), (1, 'Г', 3, 'В'), (1, 'Г', 3, 'Г'), (2, 'А', 1, 'А'), (2, 'А', 1, 'Б'), (2, 'А', 1, 'В'), (2, 'А', 1, 'Г'), (2, 'А', 2, 'А'), (2, 'А', 2, 'Б'), (2, 'А', 2, 'В'), (2, 'А', 2, 'Г'), (2, 'А', 3, 'А'), (2, 'А', 3, 'Б'), (2, 'А', 3, 'В'), (2, 'А', 3, 'Г'), (2, 'Б', 1, 'А'), (2, 'Б', 1, 'Б'), (2, 'Б', 1, 'В'), (2, 'Б', 1, 'Г'), (2, 'Б', 2, 'А'), (2, 'Б', 2, 'Б'), (2, 'Б', 2, 'В'), (2, 'Б', 2, 'Г'), (2, 'Б', 3, 'А'), (2, 'Б', 3, 'Б'), (2, 'Б', 3, 'В'), (2, 'Б', 3, 'Г'), (2, 'В', 1, 'А'), (2, 'В', 1, 'Б'), (2, 'В', 1, 'В'), (2, 'В', 1, 'Г'), (2, 'В', 2, 'А'), (2, 'В', 2, 'Б'), (2, 'В', 2, 'В'), (2, 'В', 2, 'Г'), (2, 'В', 3, 'А'), (2, 'В', 3, 'Б'), (2, 'В', 3, 'В'), (2, 'В', 3, 'Г'), (2, 'Г', 1, 'А'), (2, 'Г', 1, 'Б'), (2, 'Г', 1, 'В'), (2, 'Г', 1, 'Г'), (2, 'Г', 2, 'А'), (2, 'Г', 2, 'Б'), (2, 'Г', 2, 'В'), (2, 'Г', 2, 'Г'), (2, 'Г', 3, 'А'), (2, 'Г', 3, 'Б'), (2, 'Г', 3, 'В'), (2, 'Г', 3, 'Г'), (3, 'А', 1, 'А'), (3, 'А', 1, 'Б'), (3, 'А', 1, 'В'), (3, 'А', 1, 'Г'), (3, 'А', 2, 'А'), (3, 'А', 2, 'Б'), (3, 'А', 2, 'В'), (3, 'А', 2, 'Г'), (3, 'А', 3, 'А'), (3, 'А', 3, 'Б'), (3, 'А', 3, 'В'), (3, 'А', 3, 'Г'), (3, 'Б', 1, 'А'), (3, 'Б', 1, 'Б'), (3, 'Б', 1, 'В'), (3, 'Б', 1, 'Г'), (3, 'Б', 2, 'А'), (3, 'Б', 2, 'Б'), (3, 'Б', 2, 'В'), (3, 'Б', 2, 'Г'), (3, 'Б', 3, 'А'), (3, 'Б', 3, 'Б'), (3, 'Б', 3, 'В'), (3, 'Б', 3, 'Г'), (3, 'В', 1, 'А'), (3, 'В', 1, 'Б'), (3, 'В', 1, 'В'), (3, 'В', 1, 'Г'), (3, 'В', 2, 'А'), (3, 'В', 2, 'Б'), (3, 'В', 2, 'В'), (3, 'В', 2, 'Г'), (3, 'В', 3, 'А'), (3, 'В', 3, 'Б'), (3, 'В', 3, 'В'), (3, 'В', 3, 'Г'), (3, 'Г', 1, 'А'), (3, 'Г', 1, 'Б'), (3, 'Г', 1, 'В'), (3, 'Г', 1, 'Г'), (3, 'Г', 2, 'А'), (3, 'Г', 2, 'Б'), (3, 'Г', 2, 'В'), (3, 'Г', 2, 'Г'), (3, 'Г', 3, 'А'), (3, 'Г', 3, 'Б'), (3, 'Г', 3, 'В'), (3, 'Г', 3, 'Г')]
permutations(iterable, r)
— возвращает итератор, значениями которого являются перестановки без повторений из элементов итерируемого объекта iterable
. Если значение r
не задано, элементы итератора имеют ту же длину, что и iterable
. Иначе длина равна r
. Пример:
from itertools import permutations
values = list(permutations("АБВ"))
print(values)
Вывод программы:
[('А', 'Б', 'В'), ('А', 'В', 'Б'), ('Б', 'А', 'В'), ('Б', 'В', 'А'), ('В', 'А', 'Б'), ('В', 'Б', 'А')]
combinations(iterable, r)
— возвращает итератор, значениями которого выступают сочетания (без повторений) длиной r
элементов итерируемого объекта iterable
. Пример:
from itertools import combinations
values = list(combinations("АБВ", 2))
print(values)
Вывод программы:
[('А', 'Б'), ('А', 'В'), ('Б', 'В')]
combinations_with_replacement(iterable, r)
— возвращает итератор, значениями которого выступают сочетания (с повторениями) длиной r
элементов итерируемого объекта iterable
. Пример:
from itertools import combinations_with_replacement
values = list(combinations_with_replacement("АБВ", 2))
print(values)
Вывод программы:
[('А', 'А'), ('А', 'Б'), ('А', 'В'), ('Б', 'Б'), ('Б', 'В'), ('В', 'В')]
Напоследок рассмотрим ещё пару полезных функций.
С одной из них мы познакомились ранее — функцией enumerate()
. Она принимает на вход коллекцию, а возвращает итератор, значениями которого будут кортежи пар вида (номер элемента, значение элемента из коллекции)
. Можно дополнительно передать начало отсчёта номеров элементов (по умолчанию отсчёт идёт с 0). Пример:
for index, value in enumerate("ABC", 1):
print(index, value)
Вывод программы:
1 A 2 B 3 C
Функция enumerate()
применяется для прохода непосредственно по значениям коллекции, при этом предоставляется информация о номере каждого элемента.
Ещё одной полезной функцией является zip()
. Эта функция принимает на вход коллекции, а возвращает итератор, значениями которого выступают кортежи, состоящие из элементов, имеющих одинаковые индексы, обрабатываемых коллекций. Пример:
print(list(zip("ABC", [1, 2, 3])))
Вывод программы:
[('A', 1), ('B', 2), ('C', 3)]
Коллекции могут иметь разное количество элементов, в таком случае zip()
по умолчанию вернёт результат по самой короткой из них. Пример:
print(list(zip("ABCDE", [1, 2, 3])))
Вывод программы:
[('A', 1), ('B', 2), ('C', 3)]
Если в функции zip()
задать значение аргумента strict=True, то в случае разной длины коллекций будет вызываться исключение ValueError:
print(list(zip("ABCDE", [1, 2, 3], strict=True)))
Вывод программы:
ValueError: zip() argument 2 is shorter than argument 1
Ещё по теме
Более подробно обо всех функциях модуля itertools
можно почитать в документации.