[英]More Efficient Way to find the Second Largest Item in a List in Python
我为在整数列表中查找第二大项的简单任务编写了这个简单的代码:
def second_largest(input_list):
input_list.sort()
return input_list[-2]
但是,对于大型列表,此 function 可能真的无效,例如一百万个项目的运行时间超过 1.5 秒。
我知道这是因为 function更改了列表本身(使用 .sort 方法),这对于长列表可能非常低效。 如何在不使用更改列表的低效方法的情况下执行此任务?
谢谢大家。
以下情况如何:
lst = range(1000000)
largest, second_largest = lst[0], lst[0]
for x in lst:
if x > largest:
largest, second_largest = x, largest
elif x > second_largest:
second_largest = x
print(largest, second_largest) # 999999 999998
它只遍历一个可迭代对象一次,所以我希望它是有效的。 (当然,当len(lst) == 1
时,它有一个极端情况。在这种情况下,人们可能会争辩说不应该定义second_largest
。)
对于 100000000 个项目,我有以下速度比较:
import time
import heapq
lst = list(range(100000000))
start = time.time()
largest, second_largest = lst[0], lst[0]
for x in lst:
if x > largest:
largest, second_largest = x, largest
elif x > second_largest:
second_largest = x
print(largest, second_largest) # 999999 999998
print("Elapsed:", time.time() - start) # Elapsed: 12.085833549499512
start = time.time()
print(heapq.nlargest(2, lst)[1]) # 99999998
print("Elapsed:", time.time() - start) # Elapsed: 17.82271456718445
弹出max,再次找到max:
my_list.pop(my_list.index(max(my_list)))
max(my_list)
正如@juanpa.arrivillaga 提到的,我们可以使用堆队列算法的heapq.nlargest 方法
import heapq
data = list(range(100))
data.append(100)
print(heapq.nlargest(2, data)[1])
Output:
99
免责声明:
如果数据包含重复值,它将返回唯一的第二大元素。
我发现基于np.argpartition
的解决方案是最快的。 它确实需要 Numpy ,但它没有考虑将列表转换为 numpy 数组。 但是,最后,如果您希望进一步计算数字,您可能需要使用 numpy arrays 因为这些操作通常比列表操作快得多。 所以我假设你就是这种情况。
首先,您应该将列表转换为数组:
import numpy as np
v = list(range(10000000))
var = np.array(v)
然后我们可以使用 np.argpartition
%%time
ind = np.argpartition(var, -2)[-2]
CPU times: user 46.3 ms, sys: 25.9 ms, total: 72.2 ms
Wall time: 71.7 ms
ind = 9999998
,所以结果似乎是正确的。
现在,如果我们在这里与其他建议进行比较:
%%time
v.pop(v.index(max(v)))
max(v)
CPU times: user 619 ms, sys: 1.96 ms, total: 621 ms
Wall time: 623 ms
大约慢 10 倍
%%time
heapq.nlargest(2,v)[1]
嗯……慢得多
最后一个
largest, second_largest = v[0], v[0]
for x in v:
if x > largest:
largest, second_largest = x, largest
elif x > second_largest:
second_largest = x
print(largest, second_largest) # 999999 999998
CPU times: user 1.41 s, sys: 0 ns, total: 1.41 s
Wall time: 1.41 s
再一次,慢了很多倍。
如果您打算在某处使用 arrays,那么np.argpartition
解决方案似乎是最快的。 如果没有,您将花费大量 CPU 时间将您的列表转换为您将不再使用的数组(见下文)。 不过,它仍然优于其他一些解决方案。 如果我们考虑到数组的转换,我们会得到这样的结果:
%%time
var=np.array(v)
ind = np.argpartition(var, -2)[-2]
CPU times: user 867 ms, sys: 59 ms, total: 926 ms
Wall time: 924 ms
这个问题很好地解释了为什么这个解决方案更快。 原因是您只使用np.argpartition
执行部分排序,而不是对列表进行完全排序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.