从给定范围中选择整数

时间:2014-02-24 05:59:12

标签: python

我需要从range(1, 51)中选择6个整数,这样就不会选择两个连续的整数。 (1, 3, 6, 9, 13, 28)是有效选择,但(1, 3, 4, 9, 13, 28)不是。我需要构建一个包含所有这些可能组合的列表,每个组合都在一个元组中。生成器也可以代替列表。我知道我需要在这里使用类似itertools.combinations的东西,但我无法弄清楚如何用连续值消除元组。我写了这段代码,

>>> import itertools
>>> l = list(itertools.combinations(range(1, 51), 6))
>>> len(l)
13983816

如果对可以选择的元组没有限制,那就是我期望的长度,即50!/(44!6!)。有什么帮助吗?

3 个答案:

答案 0 :(得分:7)

您可以将all与生成器表达式一起使用:

>>> t = (1,3,4,9,13,28)
>>> all( x-y > 1 for x, y in zip(t[1:], t))
False
>>> t = (1,3,6,9,13,28)
>>> all( x-y > 1 for x, y in zip(t[1:], t))
True

<强>代码:

import itertools
for t in itertools.combinations(range(1, 20), 6):
    if all( x-y > 1 for x, y in zip(t[1:], t)):
        #do something with t

答案 1 :(得分:5)

from itertools import combinations, imap
from operator import add
from functools import partial

result = imap(partial(map, add, range(6)), combinations(range(1, 46), 6))

此解决方案利用从所需组合的双射到1到45的6个整数的所有组合的集合。我们从1到45中选择6个递增的数字x0, x1, x2, x3, x4, x5,然后计算

x0, x1+1, x2+2, x3+3, x4+4, x5+5

此新组合保证在1-50范围内且没有连续数字,并且可以通过x值的唯一选择生成任何所需组合y0, y1, y2, y3, y4, y5

y0, y1-1, y2-2, y3-3, y4-4, y5-5

这比基于滤除不需要的组合的解决方案快几倍。缺点是需要更长时间才能理解。我必须为此写出大量的解释,而另一个解决方案则更直接。使用更长的组合,该算法将具有显着的优势。例如,如果我们选择16个数字而不是6个,那么另一个算法将考虑该算法所用组合数量的大约1212倍。

答案 2 :(得分:3)

如果你考虑一下,你的第一个(最低)值不能是“任何一个50”值 - 它必须小于或等于40,因为(40, 42, 44, 46, 48, 50)是“最后一个有效元组”。在您选择的值之间必须始终有5个“未使用的值”,因此最简单的方法是从1到45中选择“无约束”值,然后将0,1,2,... 5添加到(你获得的价值。

因此:

for t in itertools.combinations(range(1,46), 6):
    print tuple(x+y for x,y in zip(t, (0,1,2,3,4,5)))

这样更有效,因为它不会生成任何不会使用的组合。你所谈论的数字很重要。原始= 50!/(44!*6!),新= 45!/(39!*6!)。这使得它的效率提高了约2倍(50*49*48*47*46*45 / (45*44*43*42*41*40))〜1.95 ...(并且感谢user2357112指出我所犯的明显算术错误 - 还有一个额外的因素6!已经悄悄上升在...)