我需要从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!)
。有什么帮助吗?
答案 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!
已经悄悄上升在...)