我想制作包含n个元素的嵌套列表,其中包含给定列表的所有排列。
预期输出如下:
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof AbstractAnimal))
return false;
AbstractAnimal other = (AbstractAnimal) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (sound == null) {
if (other.sound != null)
return false;
} else if (!sound.equals(other.sound))
return false;
return true;
}
我怎么能写一个python代码来做同样的事情。
答案 0 :(得分:7)
你可以像这样递归地解决你的问题:
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
你可以把这个函数写成两行,但我决定让它更容易理解。
不确定你对递归有多了解,但我做知道初学者不容易理解......让我试着解释一下。
在每个递归函数中,您都需要一个递归锚点。这是函数不递归但直接传递结果的点。它通常是一个定义明确的基本/原子案例。在这个例子中是n==0
的情况。由于只有一个排列,其中0个元素是空列表,因此返回包含空列表的列表。
我把n<=0
放在那里,所以如果一些smartcookie用例如烫发器调用烫发器,我们就不会遇到麻烦n=-1
,但n<0
的例外情况也适用。
现在你建立在这个锚点上并且说,好吧我的函数为n==0
提供了正确的结果,所以当我当前的n
为1并且我用n-1
调用它时我可以信任它。现在的诀窍是相信无论你从哪里开始,它都会为每个n-1
提供正确的结果!你可能想知道这是怎么回事。这就是具有递归函数的东西,当你编写它们时,你已经依赖它们做正确的工作。
现在这意味着调用perm(n-1, a)
会为您提供长度为n-1
的所有排列。然后,剩下要做的就是使用a
中的所有元素附加(或预先添加)这些排列,并且您有一个列表,其中包含大小为n
的排列!完成工作。
但请注意,有时需要使用多个锚点或锚点来处理多种输入可能性 例如着名的低效斐波那契函数:
def fib(n):
# first anchor
if n == 0:
return 0
# second anchor
if n == 1:
return 1
# recursive calls
if n < 0:
# negative if even, positive otherwise
return -fib(-n) if -n % 2 == 0 else fib(-n)
return fib(n - 2) + fib(n - 1)
需要两个锚点因为fib(n - 2)
你走了两步!
<强>跟进:强>
为什么这个功能效率低下?原因类似于斯特凡在关于我的第一个解决方案的评论中所指出的
我犯了错误,将递归调用放在循环中。这不一定是错的,但在这种情况下,调用的参数不会被外部循环改变,这使得它不必要。因此,它每次重新生成相同的列表,而不是一次生成,然后保留它。最糟糕的是所有递归实例都做了同样的事情!
你可以通过查看分支因子来看出它有多糟糕。此处fib
函数调用自身两次,这意味着它的分支因子为2。因此,如果您的解决方案需要n
步深,您将对该功能进行2^n
评估
虽然这个分支因子是常数,但我的第一个实现为a
中的每个元素调用了自己,因此分支因子等于列表中元素的数量。
我很高兴Stefan没有尝试perm(20,[1,2,3])
这将是3 ^ 20次评估,这比他尝试的2 ^ 20次评估大约多3千倍。是的,仅仅因为一个元素而增加了3千倍。这是指数运行时的行动!
为了简单起见,我忽略了问题本身已经与len(a)**n
一致的事实。
答案 1 :(得分:2)
itertools库是一个非常高效的东向使用库以及Python,根据您的要求,您可以使用此模块的product
方法来获得预期的输出,但是其他一些选项,例如permutations
,combinations
等,您也必须尝试。
import itertools
n=3
def perm(n, lst):
return list(itertools.product(lst, repeat=n))
print perm(n, [1,2])
答案 2 :(得分:2)
我意识到你要求一个递归解决方案,但这真的有必要吗?
>>> 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))