假设我有(名称,分数)形式的100个元组。我希望将9个组中的100个元组组合在一起,总组得分高于30.很好,我使用itertools.combinations(迭代,9)。问题是当我想在for循环中经历这些组合时需要“很长时间”,因为有很多组合(100!/ 91!/ 9!组合)。这是迄今为止的代码:
import time
import itertools
import csv
start_time=time.clock()
with open('data.csv') as f:
data=[tuple(line) for line in csv.reader(f)]
x = itertools.combinations(data,9)
count = 0
for i in x:
count = count +1
print count
print("--- %s seconds ---" % (time.clock() - start_time))
好吧我想通过约束组合来限制这些组合,以便组的总得分大于30.为此,我使用了itertools.combinations中的等效代码并使用了这样的约束函数:
import time
import csv
start_time=time.clock()
with open('data.csv') as f:
data=[tuple(line) for line in csv.reader(f)]
def pconstraint(combo):
totalscore=0
for player in combo:
totalscore += int(player[1])
if totalscore > 30:
return True
def combinations(iterable, r):
# combinations('ABCD', 2) --> AB AC AD BC BD CD
# combinations(range(4), 3) --> 012 013 023 123
pool = tuple(iterable)
n = len(pool)
if r > n:
return
indices = range(r)
y = tuple(pool[i] for i in indices)
if pconstraint(y):
yield y
while True:
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
else:
return
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1] + 1
x = tuple(pool[i] for i in indices)
if pconstraint(x):
yield x
count = 0
for i in x:
count = count +1
print count
print("--- %s seconds ---" % (time.clock() - start_time))
比方说,例如,当我们得分大于30的约束时,我们从(100!/ 91!/ 9!组合)变为10。使用itertools完成所有组合所需的时间.combinations(data,9)比使用约束快得多。另外,当我使用组合函数并且在没有约束变化的情况下单独运行它时,THAT也比使用约束运行得更快。我的想法是,如果发电机产生或产量较少的东西,它应该更快通过它?但显然我的想法是错的。我该怎么做才能尽快显示我想要的数据(9个元组的10个组合,得分大于30)?
答案 0 :(得分:0)
无法在itertools.combinations
中指定谓词。但是,您可以使用genex对生成器产生的结果强制执行谓词。
>>> for n in (x for x in itertools.combinations([1, 2, 3, 4], 3) if sum(x) > 7):
... print n
...
(1, 3, 4)
(2, 3, 4)
答案 1 :(得分:0)
我认为,鉴于发电机的工作原理,您所看到的内容是有道理的。对组合本身的呼吁:
x = itertools.combinations(data,9)
期望使用生成器对象返回(即在执行while
中的combinations
循环和for
中的constraint
循环之前)
将花费最多时间的代码是"解开"发电机:
for i in x:
count = count +1
通过yield
的魔法实际执行循环时的情况。所以你添加了一个约束,它应该有效地减少了产量,但是解释器仍然会在while
语句中执行相同数量的迭代乘以for
语句pconstraint
语句中的9次迭代当你迭代生成器x
时它会这样做。
考虑yield
的最简单方法是一种goto
语句,它在迭代生成器对象的代码和执行屈服的行之间来回跳转。每次从生成器请求生成的项时,执行将在最后生成的行中的combinations
内继续执行,直到它到达下一个yield,然后返回一个新项并等待(yield)以请求另一个生成的项x.next()
中隐含的for i in x
以及当它再次恢复执行时超过最后yield
等等。
希望有所帮助。