Fastest way to check if a value exist in a list
我正在寻找最快的方法来知道一个值是否存在于一个列表中(一个包含数百万值的列表),以及它的索引是什么?我知道列表中的所有值都是唯一的,就像我的示例一样。
我尝试的第一种方法是(实际代码中的3.8秒):
1 2 3 4 5 | a = [4,2,3,1,5,6] if a.count(7) == 1: b=a.index(7) "Do something with variable b" |
我尝试的第二种方法是(比实际代码快2倍:1.9秒):
1 2 3 4 5 6 7 8 | a = [4,2,3,1,5,6] try: b=a.index(7) except ValueError: "Do nothing" else: "Do something with variable b" |
StackOverflow用户提出的方法(实际代码上为2.74秒):
1 2 3 | a = [4,2,3,1,5,6] if 7 in a: a.index(7) |
在我的实际代码中,第一个方法需要3.81秒,第二个方法需要1.88秒。这是一个很好的改进,但是:
我是Python/脚本的初学者,我想知道是否存在一种最快的方法来做同样的事情并节省更多的处理时间?
对我的申请有更具体的说明:
在搅拌机的API中,A可以访问颗粒列表:
1 | particles = [1,2,3,4...etc.] |
从那里,我可以访问它的位置:
1 | particles[x].location = [x,y,z] |
我通过搜索来测试每一个粒子是否存在邻居。在每个粒子的位置,如:
1 2 3 4 | if [x+1,y,z] in particles.location "find the identity of this neighbour particles in x:the index of the particles array" particles.index([x+1,y,z]) |
1 | 7 in a |
最清晰、最快速的方法。
您也可以考虑使用
正如其他人所说,对于大的列表,
测试规范:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 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 = [] Nls = [x for x in range(1000,20000,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(math.log(method_in(a,b,c))) time_method_set_in.append(math.log(method_set_in(a,b,c))) time_method_bisect.append(math.log(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.show() |
1 2 | def check_availability(element, collection: iter): return element in collection |
用法
1 | check_availability('a', [1,2,3,4,'a','b','c']) |
我相信这是知道所选值是否在数组中的最快方法。
你可以把你的东西放进一个
尝试:
1 2 3 | s = set(a) if 7 in s: # do stuff |
在注释中编辑您说要获取元素的索引。不幸的是,集合没有元素位置的概念。另一种方法是预先对列表排序,然后在每次需要查找元素时使用二进制搜索。
1 2 3 4 5 6 7 8 9 | 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确实发生了变化,请提供有关您正在做什么的更多详细信息。
听起来您的应用程序可能从使用Bloom过滤器数据结构中获得优势。
简而言之,一个bloom过滤器查找可以很快地告诉您一个值是否在集合中不存在。否则,可以进行较慢的查找,以获取可能在列表中的值的索引。因此,如果您的应用程序倾向于比"找到"结果更频繁地得到"未找到"结果,那么您可能会看到通过添加bloom过滤器来加快速度。
有关详细信息,维基百科提供了Bloom过滤器如何工作的一个很好的概述,而"PythonBloom过滤器库"的Web搜索将提供至少两个有用的实现。
请注意,
1
2
3
4
5
6
7
8 for element in s:
if element is target:
# fast check for identity implies equality
return True
if element == target:
# slower check for actual equality
return True
return False
在大多数情况下,这个细节是不相关的,但在某些情况下,它可能会让一个新手感到惊讶,例如,
1 2 3 4 5 6 7 | >>> import numpy >>> numpy.NAN == numpy.NAN False >>> numpy.NAN is numpy.NAN True >>> numpy.NAN in [numpy.NAN] True |
为了区分这些异常情况,您可以使用
1 2 3 4 5 | >>> lst = [numpy.NAN, 1 , 2] >>> any(element == numpy.NAN for element in lst) False >>> any(element is numpy.NAN for element in lst) True |
注:带
1 | any(element is target or element == target for element in lst) |
但是,我要强调的是,这是一个边缘情况,对于绝大多数情况,
使用
ZZU1
Demo:
1 2 3 4 | >>> l=[1,2,3] >>> l.__contains__(3) True >>> |
这不是代码,而是快速搜索的算法
如果您的列表和要查找的值都是数字,那么这非常简单,如果字符串:请查看底部:
- -让"n"作为列表的长度
- -可选步骤:如果需要元素的索引:使用元素的当前索引(0到N-1)向列表中添加第二列-请参阅后面的内容
- 为列表或其副本排序(.sort())
- 循环通过:
- 将数字与列表中的n/2th元素进行比较
- 如果较大,则在索引n/2-n之间再次循环
- 如果较小,则在索引0-n/2之间再次循环
- 如果相同:你找到了
- 将数字与列表中的n/2th元素进行比较
- 不断缩小列表范围,直到找到它或只有2个数字(在您要查找的数字下方和上方)
- 对于1.000.000(对数(2)n为精确值)的列表,这将在最多19个步骤中找到任何元素。
如果还需要数字的原始位置,请在第二个索引列中查找它。
如果您的列表不是由数字组成的,那么该方法仍然有效,并且速度最快,但是您可能需要定义一个可以比较/排序字符串的函数。
当然,这需要sorted()方法的投资,但是如果您继续重用同一个列表进行检查,它可能是值得的。
对我来说是0.030s(真实),0.026s(用户)和0.004s(系统)。
1 2 3 4 5 6 7 8 9 10 11 12 | try: print("Started") x = ["a","b","c","d","e","f"] i = 0 while i < len(x): i += 1 if x[i] =="e": print("Found") except IndexError: pass |
代码检查两个元素在阵列中的存在,其中两个元素的产品等于K。
1 2 3 4 | n=len(arr1) for i in arr1: if k%i==0 : print(i) |
1 2 3 4 5 6 7 8 | present = False searchItem = 'd' myList = ['a', 'b', 'c', 'd', 'e'] if searchItem in myList: present = True print('present = ', present) else: print('present = ', present) |