获得整数排列的更有效方法?
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
编辑:也忘记添加该函数将计算相同的数字两次,留下重复,所以我也修改了。
【讨论】:
以上是关于获得整数排列的更有效方法?的主要内容,如果未能解决你的问题,请参考以下文章