Шаг 70.
Python: сборник рецептов. Итераторы и генераторы. Итерирование по всем возможным комбинациям и перестановкам

    На этом шаге мы рассмотрим некоторые возможности модуля itertools.

Задача

    Вы хотите проитерировать по всем возможным комбинациям и перестановкам коллекции элементов.

Решение

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

>>> items = ['a', 'b', 'c']
>>> from itertools import permutations
>>> for p in permutations(items):
	print(p)

	
('a', 'b', 'c')
('a', 'c', 'b')
('b', 'a', 'c')
('b', 'c', 'a')
('c', 'a', 'b')
('c', 'b', 'a')
>>>

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

>>> for p in permutations(items, 2):
	print(p)

	
('a', 'b')
('a', 'c')
('b', 'a')
('b', 'c')
('c', 'a')
('c', 'b')
>>>

    Используйте itertools.combmatiom(), чтобы создать последовательность комбинаций элементов входной последовательности. Например:

>>> from itertools import combinations
>>> for c in combinations(items, 3):
	print(c)

	
('a', 'b', 'c')
>>> for c in combinations(items, 2):
	print(c)

	
('a', 'b')
('a', 'c')
('b', 'c')
>>> for c in combinations(items, 1):
	print(c)

	
('a',)
('b',)
('c',)
>>>

    Для функции combinations() порядок элементов не имеет значения. Комбинацию ('a', 'b') она считает аналогичной ('b', 'a') - поэтому вторая в выводимых результатах отсутствует.

    При создании комбинаций выбранные элементы удаляются из коллекции возможных кандидатов (то есть если 'а' уже выбран, он больше не будет рассматриваться). А функция itertools.combinations_with_replacement() выбирает один и тот же элемент более одного раза. Например:

>>> from itertools import combinations_with_replacement
>>> for c in combinations_with_replacement(items, 3):
	print(c)

	
('a', 'a', 'a')
('a', 'a', 'b')
('a', 'a', 'c')
('a', 'b', 'b')
('a', 'b', 'c')
('a', 'c', 'c')
('b', 'b', 'b')
('b', 'b', 'c')
('b', 'c', 'c')
('c', 'c', 'c')
>>> 


Обсуждение

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

    На следующем шаге мы рассмотрим итерирование по парам "индекс-значение" последовательности.




Предыдущий шаг Содержание Следующий шаг