给定元组templates
的列表(region, calc_3d_harmonics(region))
,其中calc_3d_harmonics
是为每个区域返回签名的函数,我需要找到分数最小的区域(实际得分不高)没问题。
区域的得分由calc_harmonics_distance(calc_3d_harmonics(region),query_harmonics, radius)
给出,该函数计算给定某个半径的两个谐波签名之间的距离(query_harmonics和radius预先计算)。
我目前的解决方案是:
query_harmonics = calc_3d_harmonics(query_region)
ref_region, score = min(templates, key=lambda t: calc_3d_harmonics_distance(t[1], query_harmonics, radius))
团队成员建议我使用以下代码:
query_harmonics = calc_3d_harmonics(query_region)
ref_region, score = min([(t[0], calc_harmonics_distance(t[1], query_harmonics, radius)) for t in templates], key=lambda x: x[1])
注意:calc_3d_harmonics
和calc_harmonics_distance
都是非常缓慢而繁重的功能。此外,score
可以替换为_
。
他声称他的建议可能会带来更好的运行时间(尽管它并不重要,因为谐波功能是主要的操作)。如果min(list, key=func)
创建了一个键列表,那么我们的版本是等价的(而且我的版本更短),但是如果它每次认为我的版本都会变慢,那么它就会计算出来。
哪种方式更快?我认为必须有一个更好的(运行时间)方式来做这个(也许使用numpy?),并希望听到一些建议。
答案 0 :(得分:1)
min(lst, key=func)
在func
的每个项目上调用lst
一次(这也适用于max
,list.sort
和{{1}的关键功能})。因此,如果sorted
包含重复项,则除非使用记忆键功能,否则键功能会执行不必要的工作。
为了说明,这里有一些关键函数在调用时打印它们的arg。 lst
是一个普通的键函数,kf
使用默认的可变字典进行记忆。
kf_cached
<强>输出强>
def kf(n):
print(' Key', n)
return int(n)
def kf_cached(n, cache={}):
if n in cache:
print(' Cached', n)
return cache[n]
print(' Key', n)
cache[n] = k = int(n)
return k
a = '14142'
u = max(a, key=kf)
print('max', u, '\n')
u = max(a, key=kf_cached)
print('max', u)
答案 1 :(得分:0)
如有疑问,请不要猜测,profile it。
将所有代码放在后面,我们可以参考cPython实现。我们可以看到min
函数使用min_max
helper。
在这个助手中,我们可以找到key function is computed。
最少的摘录是:
while (( item = PyIter_Next(it) )) {
/* get the value from the key function */
if (keyfunc != NULL) {
val = PyObject_CallFunctionObjArgs(keyfunc, item, NULL);
if (val == NULL)
goto Fail_it_item;
}
/* no key function; the value is the item */
else {
val = item;
Py_INCREF(val);
}
// comparision logic for min/max
}
源代码清楚地表明,对于已排序的可迭代中的每个元素,计算一次关键函数。另一方面,排序完成后,关键功能结果被丢弃。因此,如果您计划稍后重新使用关键函数值,则可以归结为。