値がリスト(何百万もの値を含むリスト)に存在するかどうかを知るための最も速い方法は何ですか?また、そのインデックスは何ですか?
この例のように、リスト内のすべての値が一意であることを私は知っています。
私が最初に試す方法は(私の実際のコードでは3.8秒)です。
a = [4,2,3,1,5,6]
if a.count(7) == 1:
b=a.index(7)
"Do something with variable b"
私が試した2番目の方法は(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"
Stack Overflowユーザーから提案されているメソッド(私の実際のコードでは2.74秒):
a = [4,2,3,1,5,6]
if 7 in a:
a.index(7)
私の実際のコードでは、最初の方法は3.81秒かかり、2番目の方法は1.88秒かかります。これは良い改善ですが、
私はPython /スクリプティングの初心者ですが、同じことをしてより多くの処理時間を節約するより速い方法はありますか?
私のアプリケーションのためのより具体的な説明:
Blender APIでは、私は粒子のリストにアクセスすることができます。
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 particle in x:the particle's index
in the array"
particles.index([x+1,y,z])
7 in a
それを行うための最も明確かつ最速の方法。
set
を使うことも考えられますが、あなたのリストからそのセットを構築することはより速いメンバーシップテストが節約するより多くの時間がかかるかもしれません。確実にするための唯一の方法は、よくベンチマークすることです。 (これはあなたが必要とする操作にもよります)
他の人が述べたように、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()
def check_availability(element, collection: iter):
return element in collection
使用法
check_availability('a', [1,2,3,4,'a','b','c'])
これが、選択された値が配列内にあるかどうかを知るための最も早い方法であると思います。
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()の部分を一度実行してから繰り返し使用することができます。状況が変わった場合は、あなたが何をしているのかについてもっと詳しく教えてください。
あなたのアプリケーションがブルームフィルタデータ構造の使用から利益を得るかもしれないように聞こえます。
一言で言えば、値がセット内に明確に存在していない場合、ブルームフィルタルックアップは非常に迅速にあなたに伝えることができます。そうでなければ、リストの中にある可能性がある値のインデックスを得るために、より遅いルックアップをすることができます。そのため、アプリケーションが「見つかりません」という結果よりもはるかに頻繁に「見つからない」という結果を得る傾向がある場合は、ブルームフィルタを追加することで速度が向上する可能性があります。
詳細については、ウィキペディアでブルームフィルタの仕組みの概要を説明しています。また、 "pythonブルームフィルタライブラリ"をWebで検索すると、少なくとも2つの便利な実装が提供されます。
in
演算子は等価性(==
)だけでなく同一性(is
)もテストします。in
sのlist
ロジックは おおよそ同等 以下のものです(少なくとも実際にはPythonではなく、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
ほとんどの場合、この詳細は無関係ですが、状況によってはPythonの初心者に驚くかもしれません。例えば、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()
を持つin
sのlist
ロジックは次のようになります。
any(element is target or element == target for element in lst)
ただし、これはEdgeのケースであることを強調しておく必要があります。大多数のケースでは、in
演算子は非常に最適化されており、もちろんlist
またはset
を使用する必要があります。
これはコードではなく、非常に高速な検索のためのアルゴリズムです。
あなたのリストとあなたが探している値がすべて数字であれば、これはかなり簡単です。文字列の場合:一番下を見てください:
番号の元の位置も必要な場合は、2番目のインデックス列で探します。
あなたのリストが数字で作られていない場合でも、この方法はうまくいき最速ですが、文字列を比較/順序付けできる関数を定義する必要があるかもしれません。
もちろん、これにはsorted()メソッドを投資する必要がありますが、チェックのために同じリストを再利用し続ける場合は、それだけの価値があります。
または__contains__
を使用してください。
sequence.__contains__(value)
デモ:
>>> l=[1,2,3]
>>> l.__contains__(3)
True
>>>
@Winston Ewertのソリューションは、非常に大きなリストに対して大幅な高速化をもたらしますが、 this stackoverflow answer は、exceptブランチに頻繁に到達するとtry:/ except:/ else:コンストラクトが遅くなることを示します。別の方法は、dictに対して.get()
メソッドを利用することです:
a = [4,2,3,1,5,6]
index = dict((y, x) for x, y in enumerate(a))
b = index.get(7, None)
if b is not None:
"Do something with variable b"
.get(key, default)
メソッドは、キーが辞書にあることを保証できない場合にのみ使用します。キーが存在する場合、値を返します(dict[key]
と同様)。ただし、存在しない場合、.get()
はデフォルト値(ここではNone
)。この場合、選択したデフォルトがa
にないことを確認する必要があります。
私にとっては、0.030秒(実際)、0.026秒(ユーザー)、および0.004秒(sys)でした。
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
present = False
searchItem = 'd'
myList = ['a', 'b', 'c', 'd', 'e']
if searchItem in myList:
present = True
print('present = ', present)
else:
print('present = ', present)
積がkに等しい配列に2つの要素が存在するかどうかをチェックするコード。
n = len(arr1)
for i in arr1:
if k%i==0:
print(i)