我有一个循环,该循环生成数字组合,并求解以查看它们是否等于解。运行探查器后,我发现求和与解决方案的比较花费了最长的时间。这是仅是由于每个呼叫的数量,还是有一种方法可以使其更快?
Profiler输出: [名称,呼叫计数,时间(ms),自己的时间(ms)]
[listcomp,23114767,5888,5888]占总时间的25%。
[内置总和,23164699、3097、3097]占总时间的12%
现在我想不出一种缩小搜索范围的方法,因此试图节省其他时间:)
感谢您的帮助。
rangedict = {'f1': range(1850, 1910), 'f2': range(2401, 2482), 'f3': range(5150, 5850)}
coefficient = [-3, 1, 1]
possiblesolution = 1930
for combination in itertools.product(*rangedict.values()):
if solutionfound:
break
else:
currentsolution = sum([x*y for x, y in zip(coefficient, combination)])
if currentsolution == possiblesolution:
solutionfound = True
dosomething()
答案 0 :(得分:0)
:将系数直接打包到ranges
中将使整个过程加快一点:
from itertools import product
possiblesolution = 1930
solutionfound = False
rangedict2 = {'f1': range(-3*1850, -3*1910, -3),
'f2': range(2401, 2482),
'f3': range(5150, 5850)}
for combination in product(*rangedict2.values()):
if sum(combination) == possiblesolution:
solutionfound = True
print(combination[0]//(-3), combination[1], combination[2])
break
或完全不同的方法:创建一个f1
和f2
可获得的总和的字典,然后检查是否可以达到目标possiblesolution
:
from collections import defaultdict
rangedict3 = {'f1': range(-3*1850, -3*1910, -3),
'f2': range(2401, 2482),
'f3': range(5150, 5850)}
sums = {item: [[item]] for item in rangedict3['f1']}
# sums = {-5550: [[-5550]], -5553: [[-5553]], ...}
new_sums = defaultdict(list)
for sm, ways in sums.items():
for item in rangedict3['f2']:
new_sum = sm + item
for way in ways:
new_sums[new_sum].append(way + [item])
# new_sums = {-3149: [[-5550, 2401], [-5553, 2404], ...],
# -3148: [[-5550, 2402], [-5553, 2405], ...],
# ....}
for item in rangedict3['f3']:
if possiblesolution - item in new_sums:
f1_f2 = new_sums[possiblesolution - item]
print(f1_f2[0][0]//(-3), f1_f2[0][1], item)
# print(new_sums[possiblesolution - item], item)
break
那样,您还可以轻松获得其余解决方案。
或仅将f2
和f3
一起:
f1 = rangedict3['f1']
f2 = rangedict3['f2']
f3 = rangedict3['f3']
# the sums that are reachable from f2 and f3
f2_f3 = range(2401 + 5150, 2482 + 5850)
for item in f1:
if possiblesolution - item in f2_f3:
pmi = possiblesolution - item
x1 = item//(-3)
for x2 in f2:
if pmi-x2 in f3:
x3 = pmi-x2
break
print(x1, x2, x3)
break
和最后一个次要的提速:如果您真的只需要一个解决方案,则x2
和x3
仅有4种(甚至3种)可能的情况:
f1 = rangedict3['f1']
f2 = rangedict3['f2']
f3 = rangedict3['f3']
min_x2 = min(f2)
max_x2 = max(f2)
min_x3 = min(f3)
max_x3 = max(f3)
# the sums that are reachable from f2 and f3
f2_f3 = range(2401 + 5150, 2482 + 5850 - 1)
for item in f1:
if possiblesolution - item in f2_f3:
pmi = possiblesolution - item
x1 = item//(-3)
if pmi-min_x2 in f3:
x2 = min_x2
x3 = pmi-x2
elif pmi-max_x2 in f3:
x2 = max_x2
x3 = pmi-x2
elif pmi-min_x3 in f2:
x3 = min_x3
x2 = pmi-x3
# elif pmi-max_x3 in f2:
else:
x3 = max_x3
x2 = pmi-x3
print(x1, x2, x3)
break
答案 1 :(得分:0)
您正在为每个组合重做乘法。最好做
bound_dict = [['f1', [1850, 1910]], ['f2', [2401, 2482]], ['f3', [5150, 5850]]
coefficient = [-3, 1, 1]
rangedict2={bound_dict(i)[0]:range(coefficient[i]*bound_dict(i)[1][0],coefficient[i]*bound_dict(i)[1][0],coefficient[i]) for i in range(len(coefficient))}
您正在遍历所有组合,而忽略了约束消除了自由度。您应删除元素数量最多的范围,在本例中为第三个元素。这样会将迭代次数减少700倍。
for combination in itertools.product(*rangedict2.values()[:-1]):
currentsolution = sum(combination)
if possiblesolution-currentsolution in rangedict2.values()[:-1]:
solutionfound = True
dosomething()
break
您可以尝试进行列表理解:
[possiblesolution-currentsolution in rangedict2.values()[:-1] for #etc.
如果您执行的数字多于三个,则可以尝试进行嵌套的for循环,而不要使用combination
。一般的实现是这样的:
last_value1 = list(rangedict2.values()[0])[0]
last_value2 = list(rangedict2.values()[1])[0]
current_sum = last_value1+last_value2
for value1 in rangedict2.values()[0]:
current_sum = current_sum+value1-last_value1
for value2 in rangedict2.values()[1]:
current_sum = current_sum +value2-last_value2
#check whether this is a solution
last_value2 = value2
#more nested for-loops
last_value1 = value1
这样,无论rangedict2
有多长,每个迭代仅执行两个加法运算,而不是len(rangedict2)-1
运算。在这种情况下,两种情况下的结果均为2,但是在一般情况下,这可能会减少操作次数。在这种情况下,由于差异始终相同,因此您可以执行以下操作:
for value1 in (rangedict2.values()[0])):
for current_sum in range(value1+2401,value2+2482):
#check whether this is a solution