检查一个值是否存在于一个非常大的列表的最快方法是什么?
当前回答
你可以把你的物品放在一个集合里。设置查找非常有效。
Try:
s = set(a)
if 7 in s:
# do stuff
在注释中,你说你想获取元素的索引。不幸的是,集合没有元素位置的概念。另一种方法是对列表进行预先排序,然后在每次需要查找元素时使用二分搜索。
其他回答
a = [4,2,3,1,5,6]
index = dict((y,x) for x,y in enumerate(a))
try:
a_index = index[7]
except KeyError:
print "Not found"
else:
print "found"
只有在a没有改变的情况下,这才会是一个好主意,因此我们可以只执行一次dict()部分,然后重复使用它。如果a确实发生了变化,请提供更多关于您正在做什么的细节。
正如其他人所说,对于大型列表,in可能非常慢。这里比较了in, set和bisect的性能。注意时间(秒)是对数尺度。
测试代码:
import random
import bisect
import matplotlib.pyplot as plt
import math
import time
def method_in(a, b, c):
start_time = time.time()
for i, x in enumerate(a):
if x in b:
c[i] = 1
return time.time() - start_time
def method_set_in(a, b, c):
start_time = time.time()
s = set(b)
for i, x in enumerate(a):
if x in s:
c[i] = 1
return time.time() - start_time
def method_bisect(a, b, c):
start_time = time.time()
b.sort()
for i, x in enumerate(a):
index = bisect.bisect_left(b, x)
if index < len(a):
if x == b[index]:
c[i] = 1
return time.time() - start_time
def profile():
time_method_in = []
time_method_set_in = []
time_method_bisect = []
# adjust range down if runtime is too long or up if there are too many zero entries in any of the time_method lists
Nls = [x for x in range(10000, 30000, 1000)]
for N in Nls:
a = [x for x in range(0, N)]
random.shuffle(a)
b = [x for x in range(0, N)]
random.shuffle(b)
c = [0 for x in range(0, N)]
time_method_in.append(method_in(a, b, c))
time_method_set_in.append(method_set_in(a, b, c))
time_method_bisect.append(method_bisect(a, b, c))
plt.plot(Nls, time_method_in, marker='o', color='r', linestyle='-', label='in')
plt.plot(Nls, time_method_set_in, marker='o', color='b', linestyle='-', label='set')
plt.plot(Nls, time_method_bisect, marker='o', color='g', linestyle='-', label='bisect')
plt.xlabel('list size', fontsize=18)
plt.ylabel('log(time)', fontsize=18)
plt.legend(loc='upper left')
plt.yscale('log')
plt.show()
profile()
这不是代码,而是快速搜索的算法。
如果您的列表和您正在寻找的值都是数字,这是相当简单的。如果字符串:看底部:
-Let "n" be the length of your list -Optional step: if you need the index of the element: add a second column to the list with current index of elements (0 to n-1) - see later Order your list or a copy of it (.sort()) Loop through: Compare your number to the n/2th element of the list If larger, loop again between indexes n/2-n If smaller, loop again between indexes 0-n/2 If the same: you found it Keep narrowing the list until you have found it or only have 2 numbers (below and above the one you are looking for) This will find any element in at most 19 steps for a list of 1.000.000 (log(2)n to be precise)
如果您还需要您的数字的原始位置,请在第二索引列中查找。
如果您的列表不是由数字组成的,该方法仍然有效,并且将是最快的,但您可能需要定义一个可以比较/排序字符串的函数。
当然,这需要使用sorted()方法,但如果您不断重用相同的列表进行检查,那么这样做可能是值得的。
请注意,in操作符不仅测试相等性(==),还测试恒等式(is),列表的in逻辑大致相当于以下内容(实际上是用C而不是Python编写的,至少在CPython中是这样):
对于s中的元素: 如果元素是目标: #快速检查身份意味着相等 还真 如果element == target: #慢速检查实际相等 还真 返回假
在大多数情况下,这个细节是无关紧要的,但在某些情况下,它可能会让Python新手感到惊讶,例如numpy。NAN具有不等于自身的不寻常性质:
>>> import numpy
>>> numpy.NAN == numpy.NAN
False
>>> numpy.NAN is numpy.NAN
True
>>> numpy.NAN in [numpy.NAN]
True
为了区分这些不寻常的情况,你可以使用任何(),比如:
>>> lst = [numpy.NAN, 1 , 2]
>>> any(element == numpy.NAN for element in lst)
False
>>> any(element is numpy.NAN for element in lst)
True
注意,使用any()的列表的in逻辑将是:
any(element is target or element == target for element in lst)
然而,我应该强调这是一个边缘情况,对于绝大多数情况,in操作符是高度优化的,当然正是你想要的(无论是对列表还是对集合)。
7 in a
最清晰最快的方法。
您也可以考虑使用一个集合,但是从列表中构造该集合所花费的时间可能比快速成员测试所节省的时间要多。唯一确定的方法就是做好基准测试。(这也取决于你需要什么操作)
推荐文章
- 插入一行到熊猫数据框架
- 要列出Pandas DataFrame列
- 在Django模型中存储电话号码的最佳方法是什么?
- 从导入的模块中模拟函数
- 滚动或滑动窗口迭代器?
- python的方法找到最大值和它的索引在一个列表?
- 如何读取文件的前N行?
- 如何删除matplotlib中的顶部和右侧轴?
- 解析.py文件,读取AST,修改它,然后写回修改后的源代码
- Visual Studio Code:如何调试Python脚本的参数
- 如何克隆或复制一个列表在kotlin
- 使用元组/列表等等。从输入vs直接引用类型如list/tuple/etc
- 结合conda环境。Yml和PIP requirements.txt
- 将命名元组转换为字典
- 如何使x轴和y轴的刻度相等呢?