生成n乘n列表的所有排列,最大值n-1,不带递归python

时间:2014-03-12 08:49:36

标签: python algorithm recursion permutation

我想生成n乘n列表的所有排列,其中最大值为n-1,例如,对于n = 3,所有可能的列表如下所示

[0,0,0]
[0,0,1]
[0,0,2]
[0,1,0]
[0,1,1]
[0,1,2]
[0,2,0]
...
[2,2,2]

我意识到这种变化非常快(有n ^ n个排列)。我目前有以下使用递归的工作代码

def generatePermutations(allPerms, curPerm, curIndex, n):
    #allPerms is a reference to the full set of permutations
    #curIndex is the index which is currently being changed
    if (curIndex == n - 1):
        for i in range(n):
            curPerm[curIndex] = i
            allPerms.append(list(curPerm))
    else:
        for i in range(n):
            curPerm[curIndex] = i
            #recursively generate all permutations past our curIndex
            generatePermutations(allPerms, curPerm, curIndex + 1, n) 

allPermutations = []
currentPermutation = []
n = 4
for i in range(n):
    currentPermutation.append(0)

generatePermutations(allPermutations, currentPermutation, 0, n)

在尝试找到一个非递归的解决方案时,我已经碰壁了,我认为必须有n个嵌套的for循环,我无法弄清楚如何做任意的n。我所拥有的唯一想法是将某些包含循环的函数添加到列表中以某种方式运行,甚至更荒谬,以编程方式生成代码并将其传递给eval调用。我的直觉告诉我这些比必要的更复杂。谁能想到解决方案?谢谢!

2 个答案:

答案 0 :(得分:4)

简单的方法,使用库调用:

import itertools

def lists(n):
    return itertools.product(xrange(n), repeat=n)

这将返回一个迭代器,而不是一个列表。如果需要,可以通过在结果上调用list来获取列表。

如果您希望在不将作业强加到itertools的情况下执行此操作,则可以计入基数n,递增最后一位数字,并在您点击n时随身携带:

def lists(n):
    l = [0]*n
    while True:
        yield l[:]
        for i in reversed(xrange(n)):
            if l[i] != n-1:
                break
            l[i] = 0
        else:
            # All digits were n-1; we're done
            return
        l[i] += 1

答案 1 :(得分:2)

您可以一次性使用itertools.permutations()来处理整个问题:

from itertools import permutations

allPermutations = list(permutations(range(4))

该文档包含Python代码,详细说明了Python中用于该功能的替代实现;使用itertools.product()的版本,例如:

from itertools import product

def permutations(iterable, r=None):
    pool = tuple(iterable)
    n = len(pool)
    r = n if r is None else r
    for indices in product(range(n), repeat=r):
        if len(set(indices)) == r:
            yield tuple(pool[i] for i in indices)

但是,您的预期输出只是range(3)超过3的产品

>>> from itertools import product
>>> for p in product(range(3), repeat=3):
...     print p
... 
(0, 0, 0)
(0, 0, 1)
(0, 0, 2)
(0, 1, 0)
(0, 1, 1)
(0, 1, 2)
(0, 2, 0)
(0, 2, 1)
(0, 2, 2)
(1, 0, 0)
(1, 0, 1)
(1, 0, 2)
(1, 1, 0)
(1, 1, 1)
(1, 1, 2)
(1, 2, 0)
(1, 2, 1)
(1, 2, 2)
(2, 0, 0)
(2, 0, 1)
(2, 0, 2)
(2, 1, 0)
(2, 1, 1)
(2, 1, 2)
(2, 2, 0)
(2, 2, 1)
(2, 2, 2)

排列是很多更短的序列:

>>> from itertools import permutations
>>> for p in permutations(range(3)):
...     print p
... 
(0, 1, 2)
(0, 2, 1)
(1, 0, 2)
(1, 2, 0)
(2, 0, 1)
(2, 1, 0)