获得整数排列的更有效方法?

Posted

技术标签:

【中文标题】获得整数排列的更有效方法?【英文标题】:More efficient way to get integer permutations? 【发布时间】:2013-05-18 23:51:41 【问题描述】:

我可以得到这样的整数排列:

myInt = 123456789

l = itertools.permutations(str(myInt))
[int(''.join(x)) for x in l]

有没有更有效的方法在 Python 中获得 integer 排列,跳过创建字符串的开销,然后加入生成的元组?计时,元组加入过程使这比list(l) 长 3 倍。

添加支持信息

myInt =123456789
def v1(i): #timeit gives 258ms
    l = itertools.permutations(str(i))
    return [int(''.join(x)) for x in l]

def v2(i): #timeit gives 48ms
    l = itertools.permutations(str(i))
    return list(l)

def v3(i): #timeit gives 106 ms
    l = itertools.permutations(str(i))
    return [''.join(x) for x in l]

【问题讨论】:

我澄清了,比'list(l)'更长 我冒昧地发布了一些 timeit 结果来帮助澄清 OP 的问题 【参考方案1】:

你可以这样做:

>>> digits = [int(x) for x in str(123)]
>>> n_digits = len(digits)
>>> n_power = n_digits - 1
>>> permutations = itertools.permutations(digits)
>>> [sum(v * (10**(n_power - i)) for i, v in enumerate(item)) for item in permutations]
[123, 132, 213, 231, 312, 321]

这避免了与元组之间的转换,因为它将使用整数在元组中的位置来计算其值(例如,(1,2,3) 表示 100 + 20 + 3)。

因为n_digits 的值是已知的并且在整个过程中都是相同的,我认为您还可以将计算优化为:

>>> values = [v * (10**(n_power - i)) for i, v in enumerate(itertools.repeat(1, n_digits))]
>>> values
[100, 10, 1]
>>> [sum(v * index for v, index in zip(item, values)) for item in permutations]
[123, 132, 213, 231, 312, 321]

我也认为我们不需要一直打电话给zip(),因为我们不需要那个列表:

>>> positions = list(xrange(n_digits))
>>> [sum(item[x] * values[x] for x in positions) for item in permutations]
[123, 132, 213, 231, 312, 321]

【讨论】:

第一行和digits = [int(x) for x in str(123)]一样 这确实有效,但我不相信它比上面给出的 v1 更有效。谢谢! @JumBopap:我刚刚添加了一个我能想到的优化。你有没有计时而不是相信它不会更快? 我确实计时了,在我的电脑上 v1 = 0.452999830246 秒,你的第一个版本是 1.46900010109 秒,你的第二个版本是 1.35899996758 秒。 @JumBopap:谢谢,这很清楚。我添加了另一个不会一直调用zip() 的版本。不确定它是否更快,但如果没有,您是否考虑过为此编写一个小型 C 模块?然后,您可以从 Python 调用该 C 函数。【参考方案2】:

这会给你一个generator:

import itertools as it
gen = it.permutations(range(1, 10))

然后你可以遍历每个项目:

for i in gen:
    #some code

或者将其转换为列表,但这需要一些时间:

items = list(gen)

编辑:澄清你想要一个整数,也许最快的方法是使用另一个惰性评估:

gen = (int('%d%d%d%d%d%d%d%d%d' % x) for x in it.permutations(range(1, 10)))

【讨论】:

我正要说同样的话,但他的代码确实比调用列表慢得多 在这个过程中我不必遍历生成器中的每个整数,将整数转换为字符串,然后再次迭代以连接每个元组,最后将连接的元组转换回整数?【参考方案3】:

我无法评论 Simeon 的回答,所以我在这里添加。

如果你尝试用答案中的函数置换120,你会得到

[120,102,210,201,12,21]

12 和 21 是错误的答案,所以我做了修改丢弃它们:

def permute(n):
        digits = [int(x) for x in str(n)]
        n_digits = len(digits)
        n_power = n_digits - 1
        values = [v * (10**(n_power - i)) for i, v in
            enumerate(itertools.repeat(1, n_digits))]
        positions = list(range(n_digits))
        permutations = sum(item[x] * values[x] for x in positions) for
            item in itertools.permutations(digits) if item[0] > 0
        for p in permutations:
            yield p

编辑:也忘记添加该函数将计算相同的数字两次,留下重复,所以我也修改了。

【讨论】:

以上是关于获得整数排列的更有效方法?的主要内容,如果未能解决你的问题,请参考以下文章

获得 2 个 mySQL 表差异的更简单方法?

我们可以仅通过整数编码获得有效的结果吗?

在给出相似输出神经网络的情况下,获得最佳匹配对的有效方法是什么?

在某些范围更新后获得整数数组的最终状态的有效算法是什么?

确定整数位数的有效方法

确定整数位数的有效方法