Itertools

Стандартная библиотека функций языка Python дает возможность программисту создавать определенные последовательности объектов и всячески ими манипулировать. При помощи простых итераций, действующих в цикле, можно наполнять массивы неким содержимым, а пользуясь генераторами списков – задавать более сложные условия для их формирования. Подключаемый модуль itertools позволяет расширить данный функционал.

Что такое itertools?

Данное расширение является сборником полезных итераторов, повышающих эффективность работы с циклами и генераторами последовательностей объектов. Это достигается за счет лучшего управления памятью в программе, быстрого выполнения подключаемых функций, а также сокращения и упрощения кода. Готовые методы, реализованные в данной библиотеке, принимают различные параметры для управления генератором последовательности, чтобы вернуть вызывающей подпрограмме необходимый набор объектов.

В этой статье рассматривается модуль itertools, присутствующий в 3-ей версии языка Python, хотя он также доступен и для Python 2. Чтобы воспользоваться возможностями данного пакета, стоит импортировать библиотеку, предварительно указав метод, к которому будет происходить обращение в программе. Например, для вызова функции product, следует поместить в начало файла следующую инструкцию: from itertools import product. После этого программист получает возможность обращаться к методу по его имени. Если нужно использовать несколько функций — можно их названия перечислить через запятую.

Можно так же подключить модуль itertools в Python просто записав в начале программы import itertools *. При таком подключении необходимо будет обращаться к той же функции product следующим образом: itertools.product( [аргументы функции] ).

 

Бесконечная итерация

На сегодняшний день существует три функции-итератора, действие которых не прерывается автоматически.

К ним относятся методы:

  • count;
  • cycle;
  • repeat.

С помощью этих методов можно генерировать объекты или совершать определенные действия неограниченное количество раз. Это значит, что программисту потребуется самостоятельно прервать созданный цикл.

count

Данный метод создает равномерно распределенную последовательность, генерируя объекты при помощи одного или двух параметров пользователя. Первым аргументом здесь является стартовое значение набора данных, а вторым (необязательным) – длина постоянного шага. Следующий пример демонстрирует работу этого метода в небольшом цикле.

from itertools import count
for i in count(0, 2):
    if i >= 10:
        break
    else:
        print(i)

0
2
4
6
8

Как видно из результатов выполнения программы, цикл for работает с функцией count, которая в свою очередь получает стартовое значение последовательности 0 и длину шага 2. Переменная под названием i является временным хранилищем для каждого нового числа. В теле цикла используется конструкция if, ограничивающая действие генератора значением 10. Если в текущей итерации i меньше или равно 10, цикл прерывается при помощи break. В противном же случае происходит вывод значения через функцию print.

cycle

Следующий итератор позволяет создать бесконечный цикл, поочередно выводящий некие символы или числа. В качестве аргумента в данном случае выступает объект либо некий набор объектов, которые можно перечислить один за другим. Код, приведенный ниже, показывает работу функции cycle со строкой DOG в цикле for.

from itertools import cycle
count = 1
for i in cycle('DOG'):
    if count > 5:
        break
    print(i)
    count += 1

D
O
G
D
O

Таким образом, результатом работы программы становится поочередный вывод символов строки, которая является аргументом метода cycle. Поскольку данный итератор также не имеет автоматических ограничений на число новых объектов, стоит воспользоваться счетчиком для его остановки. С помощью переменной count, увеличивающей свое значение на 1 за каждый шаг цикла, эта задача решается довольно просто.

repeat

Последний из подобных итераторов осуществляет повторение объекта, который был передан в качестве первого параметра в метод. Вторым аргументом является количество идентичных элементов в создаваемой последовательности. Следующий пример показывает заполнение списка с именем data при помощи генератора с циклом for. В роли объекта здесь выступает строка DOG, которую добавляют в последовательность ровно 3 раза.

from itertools import repeat
data = [i for i in repeat('DOG', 3)]
print(data)

['DOG', 'DOG', 'DOG']

Результаты работы программы отображаются благодаря методу print, получающему готовый список data для вывода на экран. На месте первого параметра функции repeat может стоять не только строка, но и число, символ, а также другой список с любыми данными.

Комбинация значений

В данный момент имеется всего четыре функции-итератора, позволяющие комбинировать различные значения, меняя местами их составляющие. К их числу относятся такие методы как:

  • combinations;
  • combinations_with_replacement;
  • permutations;
  • product.

combinations

Первая функция по комбинированию отдельных элементов последовательности принимает два аргумента, как и все последующие. Первый позволяет задать определенный объект, а второй – количество значений, которые будут присутствовать в каждом новом отрезке. В данном примере демонстрируется работа в Python функции combinations библиотеки itertools при создании списка.

from itertools import combinations
data = list(combinations('DOG', 2))
print(data)

[('D', 'O'), ('D', 'G'), ('O', 'G')]

Как видно из кода, метод получает строку DOG, которая впоследствии раскладывается на отдельные символы. Далее происходит группировка по 2 буквы так, чтобы каждая новая выборка отличалась от всех существующих. Функция print выводит полученный список data на экран, отображая все сформированные пары символов D, O, G.

combinations_with_replacement

Более продвинутая вариация предыдущего итератора предоставляет программе возможность делать выборку из отдельных элементов с учетом их порядка. В следующем образце кода показано использование combinations_with_replacement с уже известными аргументами.

from itertools import combinations_with_replacement
for i in combinations_with_replacement('DOG', 2):
print(''.join(i))

DD
DO
DG
OO
OG
GG

В результате работы программы, на экране отобразилось несколько групп элементов, не повторяющих порядок друг друга. При этом вполне могут использоваться одинаковые объекты, если их общее расположение не совпадает с предыдущими выборками.

permutations

Работа функции permutations модуля itertools в Python похожа на комбинацию со сменой порядка. Однако в ней не допускается размещение идентичных элементов в одной группе. Ниже приведен код, демонстрирующий поведение и результат выполнения этого метода в цикле for.

from itertools import permutations
for i in permutations('DOG', 2):
    print(''.join(i))

DO
DG
OD
OG
GD
GO

На выходе программа отображает несколько пар значений, так как в качестве второго аргумента функция получила 2. Важно заметить, что каждая новая выборка отличается от всех предыдущих только порядком, а общая последовательность может включать в себя группы, состоящие из одних и тех же значений, просто сменивших расположение.

product

Последний из комбинационных итераторов получает в качестве параметра массив данных, состоящий из нескольких групп значений. Функция product библиотеки itertools в Python 3 позволяет получить из введенной последовательности чисел или символов новую совокупность групп во всех возможных вариациях. Следующий пример показывает исполнение этого метода.

from itertools import product
data = list(product((0, 1), (2, 3)))
print(data)

[(0, 2), (0, 3), (1, 2), (1, 3)]

Таким образом, получается новая последовательность data, вмещающая в себя все возможные комбинации значений, полученных из начального списка. Как и в других примерах, функция print выводит все ее содержимое на экран.

Фильтрация последовательности

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

  • filterfalse;
  • dropwhile;
  • takewhile;
  • compress.

filterfalse

Для создания нового списка из уже имеющейся последовательности объектов можно применять метод фильтрации filterfalse. В качестве первого аргумента здесь выступает проверочная функция, возвращающая булево значение True или False. Вторым параметром является список неких объектов, над которыми нужно провести фильтрацию, воспользовавшись результатом выполнения проверочной функции.

from itertools import filterfalse
data = list(filterfalse(lambda i: i == 0, [1, 2, 3, 0, 4, 5, 1]))
print(data)

[1, 2, 3, 4, 5, 1]

Как можно увидеть из примера, в лямбда-функции осуществляется проверка на равность нулю. Элементы последовательности, для которых такая проверка возвращает False, заносятся в новый список, после чего выдаются на экран.

dropwhile

Следующая функция работает несколько иным образом, хотя используется та же схема. Итератор dropwhile проверяет булево значение, возвращаемое в качестве первого параметра для каждого элемента последовательности, и в том случае, если он равен False, записывает его в новый список, а также все, что идет после.

from itertools import dropwhile
data = list(dropwhile(lambda i: i != 0, [1, 2, 3, 0, 4, 5, 1]))
print(data)

[0, 4, 5, 1]

В данном примере показано, что при помощи лямбда-функции выполняется проверка на неравенство нулю. После того как в последовательности найден 0, все последующие числовые значения сохраняются в новый список.

takewhile

Совершенно противоположным образом работает итератор takewhile, записывая в массив только те элементы, которые шли до возврата проверочной функцией значения False. Следующий пример демонстрирует работу данного метода.

from itertools import takewhile
data = list(takewhile(lambda i: i != 0, [1, 2, 3, 0, 4, 5, 1]))
print(data)

[1, 2, 3]

Как можно заметить, результирующий список получил значения, которые шли до 0.

compress

Иногда возникает необходимость в удалении ненужных объектов последовательности, просто передав ей булевы значения. Для этого используется метод compress, получающий в следующем примере строку и набор из True и False для каждого ее символа.

from itertools import compress
data = list(compress('DOG', [True, False, True]))
print(data)

['D', 'G']

В результате получается список, в котором присутствуют только элементы, отмеченные ранее как True. Символ O был удален, так как ему соответствовал False.

Прочие итераторы

Несмотря на то, что существуют инструменты библиотеки itertools, не вошедшие ни в один из описанных ранее разделов, их применение иногда также бывает очень полезным для решения многих довольно специфических задач. Часто они становятся актуальны в паре с другими итераторами. Далее будут описаны такие методы как:

  • chain;
  • chain.from_iterable
  • starmap
  • accumulate;
  • islice;
  • izip;
  • tee;
  • groupby. 

chain

Функция chain выполняет объединение списков, как это показано в следующем примере для data1 и data2. Итоговый массив содержит все элементы данных последовательностей.

from itertools import chain
data1 = ['D', 'O', 'G']
data2 = [0, 1, 2, 3, 4]
data = list(chain(data1, data2))
print(data)

['D', 'O', 'G', 0, 1, 2, 3, 4]

chain.from_iterable

Работает аналогично chain. Также выполняется объединение списков. Отличие заключается в том, что аргумент только один – вложенный список со списками, которые надо объединить.

from itertools import chain
data = [['D', 'O', 'G'], [0, 1, 2, 3, 4]]
data2 = [0, 1, 2, 3, 4]
data = list(chain.from_iterable(data))
print(data)

['D', 'O', 'G', 0, 1, 2, 3, 4]

starmap

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

from itertools import starmap
for i in starmap(pow, [(1, 2), (2, 2), (3, 2)]):
    print(i)

1
4
9

accumulate

Данная функция модуля itertools — accumulate высчитывает сумму предыдущих элементов и добавляет текущий к ней. Вот пример:

from itertools import accumulate
data = list(accumulate([1,2,3,4]))
print(data)

[1, 3, 6, 10]

Видно из кода, что первый полученный элемент равен первому заданному значению. Второй – это сумма предыдущего результата со вторым заданным значением. И так далее.

islice

Итератор islice позволяет ограничить заполнение списка новыми элементами, если ввести в качестве параметра желаемое количество объектов. Данный пример показывает совместную работу методов count и islice для создания 5 чисел, начиная с 0 и с шагом 2.

from itertools import islice
from itertools import count
for i in islice(count(0, 2), 5):
    print(i)

0
2
4
6
8

zip_longest

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

from itertools import zip_longest
for i in zip_longest('DOG', [0, 1, 2, 3], fillvalue = ' '):
    print (i)

('D', 0)
('O', 1)
('G', 2)
(' ', 3)

tee

Метод tee используется для генерации собственных итераторов на основе итерируемой последовательности объектов. В примере показано создание итераторов i1 и i2.

from itertools import tee
data = 'DOG'
i1, i2 = tee(data)
for i in i1:
    print(i)
for i in i2:
    print(i)

D
O
G
D
O
G

groupby

Последняя функция в этом разделе называется groupby и применяется для группировки объектов списка по общим значениям. Приведенный код показывает форматированную выдачу данных массива animals. Как видно из примера, метод itertools groupby принимает в качестве первого аргумента сам список, в то время как на месте второго стоит лямбда-функция.

from itertools import groupby
animals = [('CAT', 'TOM'), ('MOUSE', 'JARRY')]
for key, group in groupby(animals, lambda kind: kind[0]):
    for kind, name in group:
        print('{name} is a {kind}'.format(name = name, kind = kind))

TOM is a CAT
JARRY is a MOUSE

Резюме

Таким образом, в данной статье были описаны все методы, включенные в состав пакета itertools. Следующая таблица отображает краткую сводку по всем пройденным функциям, включая в себя особенности их вызова и назначение.

 

Название Назначение
count Итерация с заданным шагом без ограничений
cycle Итерация с повторением без ограничений
repeat Итерация с повторением заданное количество раз
combinations Комбинация всех возможных значений без повторяющихся элементов
combinations_with_replacement Комбинация всех возможных значений с повторяющимися элементами
permutations Комбинация с перестановкой всех возможных значений
product Комбинация, полученная из всех возможных значений вложенных списков
filterfalse Все элементы, для которых функция возвращает ложь
dropwhile Все элементы, начиная с того, для которого функция вернет ложь
takewhile Все элементы, до тех пор, пока функция не вернет истину
compress Удаление элементов, для которых было передано значение ложь
chain Поочередное объединение списков при помощи итераторов
chain.from_terable Аналогично chain, но аргумент – список, в который вложены объединяемые списки.
islice Получение среза, благодаря указанному количеству элементов
zip_longest Объединение нескольких итераций с повышением размера до максимального
tee Создание кортежа из нескольких готовых итераторов
groupby Группировка элементов последовательности по некоторым ключевым значениям
accumulate Каждый элемент результирующей последовательности равен сумме текущего и всех предыдущих исходной последовательности
starmap В заданную функцию передает список подставляемых аргументов

Заключение

Библиотека itertools содержит массу полезных методов. Они помогают генерировать списки, а также любые другие последовательности значений с определенными условиями. Пользуясь ее возможностями, можно заполнять наборы данных числами с итерацией, комбинировать символы строк и фильтровать элементы массива по признакам. В данной статье описаны все методы библиотеки itertools, содержащиеся в официальной документации Python 3. Для большей наглядности приведены подробные примеры использования функций.