我目前有一个使用lambda函数f排序的长列表。然后我从前五个元素中选择一个随机元素。类似于:
f = lambda x: some_function_of(x, local_variable)
my_list.sort(key=f)
foo = choice(my_list[:4])
根据分析器,这是我的程序中的瓶颈。我该如何加快速度?是否有一种快速的内置方法来检索我想要的元素(理论上不需要对整个列表进行排序)?谢谢。
使用heapq.nlargest
或heapq.nsmallest
。
例如:
import heapq
elements = heapq.nsmallest(4, my_list, key=f)
foo = choice(elements)
当K相对于N很小时,此方法将以O(N+KlogN)的时间复杂度运行,其中K是返回的元素数量,N是列表大小。相对于正常排序的O(NlogN),此方法更快。
在平均情况下,它实际上可以在线性时间(O(N))内完成。
您需要一个分区算法:
def partition(seq, pred, start=0, end=-1):
if end == -1: end = len(seq)
while True:
while True:
if start == end: return start
if not pred(seq[start]): break
start += 1
while True:
if pred(seq[end-1]): break
end -= 1
if start == end: return start
seq[start], seq[end-1] = seq[end-1], seq[start]
start += 1
end -= 1
可以被nth_element算法使用:
def nth_element(seq_in, n, key=lambda x:x):
start, end = 0, len(seq_in)
seq = [(x, key(x)) for x in seq_in]
def partition_pred(x): return x[1] < seq[end-1][1]
while start != end:
pivot = (end + start) // 2
seq[pivot], seq[end - 1] = seq[end - 1], seq[pivot]
pivot = partition(seq, partition_pred, start, end)
seq[pivot], seq[end - 1] = seq[end - 1], seq[pivot]
if pivot == n: break
if pivot < n: start = pivot + 1
else: end = pivot
seq_in[:] = (x for x, k in seq)
鉴于这些,只需将第二行(排序)替换为以下内容:
nth_element(my_list, 4, key=f)
some_function_of
是昂贵的吗? - SilentGhost