itertools: Декартово произведение перестановок

Используя pythons itertools, я хотел бы создать итератор для внешнего продукта всех перестановок группы списков. Явный пример:

import itertools
A = [1,2,3]
B = [4,5]
C = [6,7]

for x in itertools.product(itertools.permutations(A),itertools.permutations(B),itertools.permutations(C)):
    print x

Хотя это работает, я хотел бы обобщить его на произвольный список списков. Я старался:

for x in itertools.product(map(itertools.permutations,[A,B,C])):
    print x

но это не сделало то, что я намеревался. Ожидаемый результат:

((1, 2, 3), (4, 5), (6, 7))
((1, 2, 3), (4, 5), (7, 6))
((1, 2, 3), (5, 4), (6, 7))
((1, 2, 3), (5, 4), (7, 6))
((1, 3, 2), (4, 5), (6, 7))
((1, 3, 2), (4, 5), (7, 6))
((1, 3, 2), (5, 4), (6, 7))
((1, 3, 2), (5, 4), (7, 6))
((2, 1, 3), (4, 5), (6, 7))
((2, 1, 3), (4, 5), (7, 6))
((2, 1, 3), (5, 4), (6, 7))
((2, 1, 3), (5, 4), (7, 6))
((2, 3, 1), (4, 5), (6, 7))
((2, 3, 1), (4, 5), (7, 6))
((2, 3, 1), (5, 4), (6, 7))
((2, 3, 1), (5, 4), (7, 6))
((3, 1, 2), (4, 5), (6, 7))
((3, 1, 2), (4, 5), (7, 6))
((3, 1, 2), (5, 4), (6, 7))
((3, 1, 2), (5, 4), (7, 6))
((3, 2, 1), (4, 5), (6, 7))
((3, 2, 1), (4, 5), (7, 6))
((3, 2, 1), (5, 4), (6, 7))
((3, 2, 1), (5, 4), (7, 6))

person Hooked    schedule 22.08.2012    source источник


Ответы (1)


Вы пропустили *, чтобы распаковать список в 3 аргумента

itertools.product(*map(itertools.permutations,[A,B,C]))
person JBernardo    schedule 22.08.2012
comment
Это решает указанную проблему, но имеет неприятный побочный эффект расширения перестановок до полных списков, что полностью подрывает намерение итератора. Когда один из списков имеет даже средний размер, скажем, 13, N! становится огромным числом при сохранении в памяти. - person Hooked; 22.08.2012
comment
@Нет! Он расширит список с 3 итераторами в 3 аргументах (которые все еще являются итераторами) - person JBernardo; 22.08.2012
comment
Пусть A=range(13) и то же самое для B и C. Конечно, в этом итераторе 13!**3 элементов, но мы должны иметь возможность пройтись по ним (в этом весь смысл итераторов, верно?). Использование памяти взрывается, прежде чем он перечисляет один. Попробуйте - у вас нет такого же эффекта? - person Hooked; 22.08.2012
comment
@Hooked, это произойдет и в вашей оригинальной версии. Это какая-то проблема, связанная с product... Я попытаюсь проверить позже (но оба кода работают одинаково) - person JBernardo; 23.08.2012
comment
@Зацепило, теперь я помню! Это довольно просто: product нужно преобразовать ваши итераторы в списки раньше, потому что их нужно зацикливать много раз (а итератор можно использовать только один раз) - person JBernardo; 23.08.2012
comment
Это полезно знать, хотя кажется, что должен быть способ повторить итераторы (скажем, с помощью itertools.cycle), чтобы продукт не преобразовывал их. Я попытаюсь задать его как новый вопрос (stackoverflow.com/questions/12093364/), поскольку вы уже решили эту проблему. Спасибо еще раз! - person Hooked; 23.08.2012