Python 中单个列表的 n 重笛卡尔积

n-fold Cartesian product on a single list in Python

如何在Pyhton中以优雅(简洁)的方式计算列表上的n次笛卡尔积,即A × ... × A(n次)?

此问题与 Get the cartesian product of a series of lists? 不重复。我不希望一系列列表的笛卡尔积相互交叉。我想要单个列表的笛卡尔积与自身交叉 n 次,其中 n 是给函数的参数。

示例:

l = ["a", "b", "c"]
> cart_prod(l, 0)
[]
> cart_prod(l, 1)
[('a',), ('b',), ('c',)]
> cart_prod(l, 2)
[('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'b'), ('b', 'c'), ('c', 'a'), ('c', 'b'), ('c', 'c')]
> cart_prod(l, 3)
[('a', 'a', 'a'), ('a', 'a', 'b'), ('a', 'a', 'c'), ('a', 'b', 'a'), ('a', 'b', 'b'), ('a', 'b', 'c'), ('a', 'c', 'a'), ('a', 'c', 'b'), ('a', 'c', 'c'), ('b', 'a', 'a'), ('b', 'a', 'b'), ('b', 'a', 'c'), ('b', 'b', 'a'), ('b', 'b', 'b'), ('b', 'b', 'c'), ('b', 'c', 'a'), ('b', 'c', 'b'), ('b', 'c', 'c'), ('c', 'a', 'a'), ('c', 'a', 'b'), ('c', 'a', 'c'), ('c', 'b', 'a'), ('c', 'b', 'b'), ('c', 'b', 'c'), ('c', 'c', 'a'), ('c', 'c', 'b'), ('c', 'c', 'c')]

我想出了以下迭代解决方案:

def cart_prod(l, n):
    if n == 0:
        return []  # compute the result for n = 0
    # preliminarily, create a list of lists instead of a list of tuples
    res = [[x] for x in l]  # initialize list with singleton tuples (n = 1)
    for i in range(n-1):
        res = [r + [x] for r in res for x in l]  # concatenate each n-1 tuple with each element from a
    res = [tuple(el) for el in res]  # turn the list of lists into a list of tuples
    return res

这段代码可以完成工作,但是是否有更短的、可能是一行的定义,可能是嵌套列表理解或 lambda 表达式?我对更紧凑的解决方案感兴趣,不一定更易读。

itertools.product 采用关键字参数来指示给定的参数应该重复。

>>> from itertools import product
>>> list(product([1,2], repeat=0))
[()]
>>> list(product([1,2], repeat=1))
[(1,), (2,)]
>>> list(product([1,2], repeat=2))
[(1, 1), (1, 2), (2, 1), (2, 2)]

这也适用于多个可迭代对象。

# Equivalent to list(product([1,2], ['a', 'b'], [1,2], ['a', 'b']))
>>> list(product([1,2], ['a', 'b'], repeat=2))
[(1, 'a', 1, 'a'), (1, 'a', 1, 'b'), (1, 'a', 2, 'a'), (1, 'a', 2, 'b'), (1, 'b', 1, 'a'), (1, 'b', 1, 'b'), (1, 'b', 2, 'a'), (1, 'b', 2, 'b'), (2, 'a', 1, 'a'), (2, 'a', 1, 'b'), (2, 'a', 2, 'a'), (2, 'a', 2, 'b'), (2, 'b', 1, 'a'), (2, 'b', 1, 'b'), (2, 'b', 2, 'a'), (2, 'b', 2, 'b')]