itertools:排列的笛卡尔积

3
使用Python的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))
1个回答

12
你漏掉了用*将列表解包成三个参数。
itertools.product(*map(itertools.permutations,[A,B,C]))

这解决了所述的问题 - 但它有一个不幸的副作用,即将排列组合扩展到完整列表中,完全破坏了迭代器的意图。当其中一个列表甚至是中等大小时(比如13),N!在存储在内存中时会变成一个巨大的数字。 - Hooked
1
@Hooked 不行!它会用三个迭代器扩展列表(这些迭代器仍然是迭代器)。 - JBernardo
A=range(13)BC 同理。虽然这个迭代器中有 13!**3 个元素,但我们应该能够遍历它们(这就是迭代器的全部意义,对吧?)。但在列出任何一个元素之前,内存使用量就会爆炸。你试试看 - 你没有同样的效果吗? - Hooked
@Hooked,在您的原始版本中也会发生这种情况。这是一些与“产品”相关的问题...我稍后会试着检查一下(但两个代码运行方式相同)。 - JBernardo
1
@Hooked 现在我记起来了!很简单:product 需要在使用之前将你的迭代器转换为列表,因为它们需要被循环多次(而迭代器只能使用一次)。 - JBernardo
这很好知道 - 虽然似乎应该有一种方法可以重复迭代器(比如使用itertools.cycle),以便product不对它们进行转换。我将尝试提出一个新问题询问(https://dev59.com/Smct5IYBdhLWcg3wcs-G),因为您已经解决了这个问题。再次感谢! - Hooked

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接