python 迭代中的数字排列

Number permutations in python iterative

我需要生成数字排列,数字可以大于数字计数。对于我目前的目的,我需要生成这些数字的排列 0, 1, 2 以获得最多 20 位数字的长度。例如,我的前几个排列是 0, 1, 2, 10, 11, 12, ... 1122, 1211.

在 Python here or here 中有使用迭代器的现有答案,这些答案直接给出了完整的排列。

但我需要对每个排列进行一些测试,如果我将整个排列列表保存在内存中,它会变得太大,尤其是对于 20 位数字,它会达到 320 个排列.

所以我的问题是它是否可以不用递归来完成,这样我就可以对每个排列进行测试。

编辑:

我正在查看具有重复的排列。因此,对于 20 个数字,每个数字都可以从 [0, 1, 2] 中获取值。这就是为什么这种情况下的排列数会达到 320.

是的,您的程序可能是这样的:

import itertools


def perform_test(permutation):
    pass

# permutations() does not construct entire list, but yields 
# results one by on.
for permutation in itertools.permutations([1, 2, 3, 4, 5], 2):
    perform_test(permutation)

虽然有一些方法可以使用 itertools 等来执行此操作,但这里的方法与您通常使用的方法略有不同。

如果您要按顺序列出这些排列,您实际拥有的是代表它们在列表中位置的三进制数。例如list[4] 是 11,即三进制中的 4 (3*1+1*1)。因此,您可以将要测试的索引值转换为三进制,这将产生正确的值。

虽然 python 可以将整数转换为它在该基数中的形式(例如 int("11",3) 输出 4),但反向操作并未隐式实现。虽然有很多实现。 Here 是一个很好的(根据您的情况修改):

def digit_to_char(digit):
    if digit < 10:
        return str(digit)
    return chr(ord('a') + digit - 10)

def perm(number):
    (d, m) = divmod(number, 3)
    if d > 0:
        return perm(d) + digit_to_char(m)
    return digit_to_char(m)

所以如果你想找到第 20 个排列,你可以执行 perm(20),这会得到 202。所以现在你可以通过你想要的索引值进行常规循环。内存中没有存储大列表。

permutation = 0
i = 0
while len(str(permutation)) < 20:
    permutation = perm(i)
    do_test(permutation)
    i += 1

您正在寻找的是笛卡尔积,而不是排列。 Python itertools 有一个方法 itertools.product() 可以产生所需的结果:

import itertools

for p in itertools.product(range(3), repeat=4):
    print p

输出为 3^4 行:

(0, 0, 0, 0)
(0, 0, 0, 1)
(0, 0, 0, 2)
(0, 0, 1, 0)
(0, 0, 1, 1)
...
(2, 2, 2, 1)
(2, 2, 2, 2) 

要生成长度为 1 到 4 的输出元组,请使用额外的迭代:

for l in range(1, 5):
    for p in itertools.product(range(3), repeat=l):
        print p

最后,这也适用于字符串元素:

for i in range(5):
    for p in itertools.product(('0', '1', '2'), repeat=i):
        print ''.join(p),
print

输出:

0 1 2 00 01 02 10 11 12 20 21 22 000 001 002 010 [...] 2220 2221 2222