我正在寻找最快的方法来知道一个值是否存在于一个列表中(一个包含数百万值的列表),以及它的索引是什么?我知道列表中的所有值都是唯一的,就像我的示例一样。
我尝试的第一种方法是(实际代码中的3.8秒):
a = [4,2,3,1,5,6]
if a.count(7) == 1:
b=a.index(7)
"Do something with variable b"
我尝试的第二种方法是(比实际代码快2倍:1.9秒):
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秒):
a = [4,2,3,1,5,6]
if 7 in a:
a.index(7)
在我的实际代码中,第一个方法需要3.81秒,第二个方法需要1.88秒。这是一个很好的改进,但是:
我是Python/脚本的初学者,我想知道是否存在一种最快的方法来做同样的事情并节省更多的处理时间?
对我的申请有更具体的说明:
在搅拌机的API中,A可以访问颗粒列表:
particles = [1,2,3,4...etc.]
从那里,我可以访问它的位置:
particles[x].location = [x,y,z]
我通过搜索来测试每一个粒子是否存在邻居。在每个粒子的位置,如:
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])
在Python中,方括号中的内容称为列表,而不是数组。与其使用列表,不如使用集合。或者保持列表的排序,使用bisect模块
所以你真的需要调整指数吗?或者,命令实际上并不重要,而您只想进行成员船测试、交叉点等?换句话说,这取决于你真正想做什么。集合可能对您有用,然后它们是一个很好的答案,但是我们无法从您显示的代码中分辨出来。
可能您必须在问题中指定不需要值,而需要它的索引。
我编辑我的问题,试图更清楚地解释我想做什么…我希望如此…
@stevenrumbalski:因为集合不能包含重复内容,而jean想要存储粒子的位置(x,y,z可以相同),所以在这种情况下我们不能使用集合。
7 in a
最清晰、最快速的方法。
您也可以考虑使用set,但是从您的列表中构造该集合可能需要比更快的成员资格测试节省更多的时间。唯一能确定的方法就是做好基准。(这还取决于您需要什么操作)
但是你没有索引,得到它将花费你所保存的。
比如:如果a:b=a.index(7)中有7个?
@Stevenrumbalski:如果您不需要订购,集合只是一个选项(因此,有一个索引)。答案中清楚地提到了集合,它也给出了一个简单的答案,正如OP所要求的那样。我认为这不值得-1。
我编辑我的问题,试图更清楚地解释我想做什么…我希望如此…
好的,我在我的代码中尝试了你的方法,这可能需要更多的时间,因为我需要知道这个值的索引。使用第二种方法,我检查它是否存在,并同时获取索引。
@如果您只需要索引,请使用第二种方法。
正如其他人所说,对于大的列表,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 = []
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()
喜欢剪切粘贴,可执行代码这样的答案。为了节省别人几秒钟的时间,您需要3种进口产品:import random / import bisect / import matplotlib.pyplot as plt,然后拨打:profile()。
这是什么版本的python?
获取代码总是很好的,但是我必须提前输入运行时间。
别忘了卑微的range()对象。当使用var in [integer list]时,查看range()对象是否可以模拟相同的序列。性能非常接近一套,但更简洁。
def check_availability(element, collection: iter):
return element in collection
用法
check_availability('a', [1,2,3,4,'a','b','c'])
我相信这是知道所选值是否在数组中的最快方法。
EDOCX1?0?
您需要将代码放入定义:def listvalue():a=[1,2,3,4,'a'、'b'、'c']返回x=listvalue()print(x)中的"a"
这是一个有效的python答案,它只是不好的、可读的代码。
当心!虽然这很可能是你没有预料到的:o='--skip'; o in ("--skip-ias"); # returns True !。
@alex f the in运算符的工作方式与测试子字符串成员身份的工作方式相同。这里令人困惑的部分可能是,("hello")不是单值元组,而("hello",)是--逗号起作用。o in ("--skip-ias",)是预期的False。
你可以把你的东西放进一个set里。设置查找非常有效。
尝试:
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确实发生了变化,请提供有关您正在做什么的更多详细信息。
它在工作,但在我的代码中实现时不起作用:"类型错误:不可显示的类型:'list'
@Jean-Francoisgallant,这可能是因为您使用的列表实际上应该使用元组。如果您想获得有关如何加快代码速度的全面建议,应该将其发布到codereview.stackexchange.com。在那里你会得到风格和性能建议。
这是解决这个问题的一个非常聪明的方法。我不使用try-except构造,而是使用:a_index=index.get(7),如果找不到键,它将默认为none。
听起来您的应用程序可能从使用Bloom过滤器数据结构中获得优势。
简而言之,一个bloom过滤器查找可以很快地告诉您一个值是否在集合中不存在。否则,可以进行较慢的查找,以获取可能在列表中的值的索引。因此,如果您的应用程序倾向于比"找到"结果更频繁地得到"未找到"结果,那么您可能会看到通过添加bloom过滤器来加快速度。
有关详细信息,维基百科提供了Bloom过滤器如何工作的一个很好的概述,而"PythonBloom过滤器库"的Web搜索将提供至少两个有用的实现。
请注意,in操作符不仅测试等式(==而且测试同一性(is),list的in逻辑大致相当于以下内容(实际上它是用C而不是用python编写的,至少在c python中是这样的):
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
在大多数情况下,这个细节是不相关的,但在某些情况下,它可能会让一个新手感到惊讶,例如,numpy.NAN具有不等于自身的异常属性:
>>> import numpy
>>> numpy.NAN == numpy.NAN
False
>>> numpy.NAN is numpy.NAN
True
>>> numpy.NAN in [numpy.NAN]
True
为了区分这些异常情况,您可以使用any(),例如:
>>> 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()的lists的in逻辑为:
any(element is target or element == target for element in lst)
但是,我要强调的是,这是一个边缘情况,对于绝大多数情况,in运算符都是高度优化的,并且完全符合您的需要(使用list或set)。
nan==nan返回false没有什么异常。这是IEEE 754标准中定义的行为。
使用__contains__
ZZU1
Demo:
>>> l=[1,2,3]
>>> l.__contains__(3)
True
>>>
这不是代码,而是快速搜索的算法
如果您的列表和要查找的值都是数字,那么这非常简单,如果字符串:请查看底部:
-让"n"作为列表的长度
-可选步骤:如果需要元素的索引:使用元素的当前索引(0到N-1)向列表中添加第二列-请参阅后面的内容
为列表或其副本排序(.sort())
循环通过:
将数字与列表中的n/2th元素进行比较
如果较大,则在索引n/2-n之间再次循环
如果较小,则在索引0-n/2之间再次循环
如果相同:你找到了
不断缩小列表范围,直到找到它或只有2个数字(在您要查找的数字下方和上方)
对于1.000.000(对数(2)n为精确值)的列表,这将在最多19个步骤中找到任何元素。
如果还需要数字的原始位置,请在第二个索引列中查找它。
如果您的列表不是由数字组成的,那么该方法仍然有效,并且速度最快,但是您可能需要定义一个可以比较/排序字符串的函数。
当然,这需要sorted()方法的投资,但是如果您继续重用同一个列表进行检查,它可能是值得的。
你忘了提到你解释的算法是一个简单的二进制搜索。
对我来说是0.030s(真实),0.026s(用户)和0.004s(系统)。
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。
n=len(arr1)
for i in arr1:
if k%i==0 :
print(i)
present = False
searchItem = 'd'
myList = ['a', 'b', 'c', 'd', 'e']
if searchItem in myList:
present = True
print('present = ', present)
else:
print('present = ', present)