这是一个相当基本的迭代有序组合制造商,它采用回调函数。它不像BrenBarn的解决方案那样具有多功能性,但它确实跳过了产生如问题中指定的产品:如果回传失败时,如果通过参数seq
,返回False
(或者false-ish),那么combo
将跳过生成那些以seq[:-1]
。
def combo(n, k, callback):
a = list(range(k))
ok = callback(a)
k -= 1
while True:
i = k
if not ok: i -= 1
while True:
a[i] += 1
if a[i] == (n + i - k):
i -= 1
if i < 0:
return
else:
break
v = a[i] + 1
a[i+1:] = range(v, v + k - i)
ok = callback(a)
# test
n = 8
k = 4
def do_something(seq):
s = sum(seq)
ok = s <= seq[-2] * 3
print(seq, s, ok)
return ok
combo(n, k, do_something)
输出
[0, 1, 2, 3] 6 True
[0, 1, 2, 4] 7 False
[0, 1, 3, 4] 8 True
[0, 1, 3, 5] 9 True
[0, 1, 3, 6] 10 False
[0, 1, 4, 5] 10 True
[0, 1, 4, 6] 11 True
[0, 1, 4, 7] 12 True
[0, 1, 5, 6] 12 True
[0, 1, 5, 7] 13 True
[0, 1, 6, 7] 14 True
[0, 2, 3, 4] 9 True
[0, 2, 3, 5] 10 False
[0, 2, 4, 5] 11 True
[0, 2, 4, 6] 12 True
[0, 2, 4, 7] 13 False
[0, 2, 5, 6] 13 True
[0, 2, 5, 7] 14 True
[0, 2, 6, 7] 15 True
[0, 3, 4, 5] 12 True
[0, 3, 4, 6] 13 False
[0, 3, 5, 6] 14 True
[0, 3, 5, 7] 15 True
[0, 3, 6, 7] 16 True
[0, 4, 5, 6] 15 True
[0, 4, 5, 7] 16 False
[0, 4, 6, 7] 17 True
[0, 5, 6, 7] 18 True
[1, 2, 3, 4] 10 False
[1, 2, 4, 5] 12 True
[1, 2, 4, 6] 13 False
[1, 2, 5, 6] 14 True
[1, 2, 5, 7] 15 True
[1, 2, 6, 7] 16 True
[1, 3, 4, 5] 13 False
[1, 3, 5, 6] 15 True
[1, 3, 5, 7] 16 False
[1, 3, 6, 7] 17 True
[1, 4, 5, 6] 16 False
[1, 4, 6, 7] 18 True
[1, 5, 6, 7] 19 False
[2, 3, 4, 5] 14 False
[2, 3, 5, 6] 16 False
[2, 3, 6, 7] 18 True
[2, 4, 5, 6] 17 False
[2, 4, 6, 7] 19 False
[2, 5, 6, 7] 20 False
[3, 4, 5, 6] 18 False
[3, 4, 6, 7] 20 False
[3, 5, 6, 7] 21 False
[4, 5, 6, 7] 22 False
如果您注释掉if not ok: i -= 1
线会产生所有组合。
此代码可以很容易地修改为做更大的跳过。我们不用回调函数中的布尔返回值,而是返回所需的跳转级别。如果它返回零,那么我们不会做任何跳过。如果它返回1,那么我们跳过以上述版本开头的子序列seq[:-1]
。如果回调返回2,然后我们跳过与seq[:-2]
开始的子序列等
def combo(n, k, callback):
a = list(range(k))
skips = callback(a)
k -= 1
while True:
i = k - skips
while True:
a[i] += 1
if a[i] == (n + i - k):
i -= 1
if i < 0:
return
else:
break
v = a[i] + 1
a[i+1:] = range(v, v + k - i)
skips = callback(a)
不要在列表做'的子集(产品(*套)):'...离开了'list',这迫使你将整个'product'物化成内存,并且避免了懒惰地遍历'product'的内存效率。既然你没有保留它,那只是毫无意义的低效率。 –
如果你使用'product'或'combinations'等itertools,他们总是会生成所有的组合。你不能让它做一个内部的'break'。 *您可以通过存储“失败”的情况下跳过组合,检查最后一个元素,并使用“继续”移动到下一个,但你仍然会得到每个元素。 – BrenBarn
我仍然不明白如何使用'产品'帮助。 –