如何使用递归函数创建包含n个元素的列表置换列表?|python

如何使用递归函数创建包含n个元素的列表置换列表?|python,python,python-2.7,Python,Python 2.7,我想制作一个包含n个元素的嵌套列表,其中包含给定列表的所有排列 预期输出如下所示: n=3 print perm(n, [1,2]) [[1,1,1],[1,1,2],[1,2,1],[1,2,2],[2,1,1],[2,1,2],[2,2,1],[2,2,2]] 我怎样才能编写一个python代码来完成同样的工作。该库是python附带的一个非常高效且易于使用的库,根据您的要求,您可以使用此模块的product方法来获得预期的输出,但还有一些其他选项,如排列,组合等,您也必须尝试 impo

我想制作一个包含n个元素的嵌套列表,其中包含给定列表的所有排列

预期输出如下所示:

n=3
print perm(n, [1,2])

[[1,1,1],[1,1,2],[1,2,1],[1,2,2],[2,1,1],[2,1,2],[2,2,1],[2,2,2]]
我怎样才能编写一个python代码来完成同样的工作。

该库是python附带的一个非常高效且易于使用的库,根据您的要求,您可以使用此模块的
product
方法来获得预期的输出,但还有一些其他选项,如
排列
组合
等,您也必须尝试

import itertools
n=3

def perm(n, lst):
    return list(itertools.product(lst, repeat=n))

print perm(n, [1,2])

您可以像这样递归地解决问题:

def perm(n, a):
  # recursion anchor
  if n <= 0:
    return [[]]
  else:
    result = []
    for smallPerm in perm(n-1, a):
      # take all elements from a
      for elem in a:
        # and prepend them to all permutations we get from perm(n-1, 1)
        result.append([elem] + smallPerm)
    return result
需要两个锚,因为使用
fib(n-2)
可以后退两步

跟进:

为什么这个功能效率低下?原因与Stefan在关于我的第一个解决方案的评论中指出的相似。
我犯了一个错误,把递归调用放在一个循环中。这并不一定是错误的,但是在这种情况下,调用的参数没有被外部循环更改,这使得调用变得不必要。因此,它每次都会重新生成相同的列表,而不是只生成一次然后再保存。最糟糕的是,所有递归实例都是这样做的
通过观察分支因子,可以看出这有多糟糕。这里的
fib
函数调用自己两次,这意味着它的分支因子为2。因此,如果您的解决方案需要深入执行
n
步骤,您将对该函数进行
2^n
评估。
虽然这个分支因子是常量,但我的第一个实现为
a
中的每个元素调用了自己,因此分支因子等于列表中的元素数。
我很高兴Stefan没有尝试
perm(20,[1,2,3])
这将是3^20次评估,大约是他尝试的2^20次评估的3000倍。是的,增加了3000倍仅仅是因为增加了一种元素。这是指数运行时在运行

为了简单起见,我忽略了一个事实,即问题本身已经随着
len(a)**n

而扩展,我知道您要求递归解决方案,但这真的有必要吗

>>> from itertools import product
>>> list(product([1, 2], repeat=3))
[(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), (2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2)]
或者,如果您确实需要内部列表:

>>> from itertools import product
>>> map(list, product([1, 2], repeat=3))
[[1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 2, 2], [2, 1, 1], [2, 1, 2], [2, 2, 1], [2, 2, 2]]
如果你真的不需要整个列表,只想处理三元组,
product
单独完成这项工作:

>>> from itertools import product
>>> for triple in product([1, 2], repeat=3):
        print(triple)

(1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 2, 2)
(2, 1, 1)
(2, 1, 2)
(2, 2, 1)
(2, 2, 2)
递归解决方案:

def perm(elements, n):
    return [[e] + p for p in perm(elements, n-1) for e in elements] if n else [[]]

print(perm([1, 2], 3))

到目前为止你试过什么?提供代码不是堆栈的目的,您当前的函数是否不起作用,或者它是用另一种语言编写的,我们可以帮助将其翻译成python?看看python文档中的itertools。这些不是排列。这是一个笛卡尔乘积。只需执行
列表(itertools.product(lst,repeat=n))
,无需理解任何内容。ok编辑@你是最棒的!谢谢你非常详细的回答。真的帮助我理解TNAD。你能把两行的答案加上吗?这样我就可以比较并学习如何使用它了。@Sharontarab我在我的答案上加了一行。它也更有效,因为我使用了两个循环的正确顺序,因此递归调用的数量是线性的而不是指数的。谢谢Stefan!我将查找:)@swenzel最好交换循环的顺序,以避免递归调用的指数数量。当然,我们有指数运行时,因为结果是指数大小,但它仍然是缓慢和坏的一般。我刚刚测试了perm(20[1,2]),耗时45.8秒。交换循环后,耗时6.7秒。讨论这个问题甚至可能是对你的优秀答案的一个很好的补充。
def perm(elements, n):
    return [[e] + p for p in perm(elements, n-1) for e in elements] if n else [[]]

print(perm([1, 2], 3))