web-dev-qa-db-ja.com

値がリストに存在するかどうかを確認する最も早い方法

値がリスト(何百万もの値を含むリスト)に存在するかどうかを知るための最も速い方法は何ですか?また、そのインデックスは何ですか?

この例のように、リスト内のすべての値が一意であることを私は知っています。

私が最初に試す方法は(私の実際のコードでは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])
648
7 in a

それを行うための最も明確かつ最速の方法。

setを使うことも考えられますが、あなたのリストからそのセットを構築することはより速いメンバーシップテストが節約するより多くの時間がかかるかもしれません。確実にするための唯一の方法は、よくベンチマークすることです。 (これはあなたが必要とする操作にもよります)

1277
Rafe Kettler

他の人が述べたように、inは大きなリストではとても遅くなる可能性があります。 inset、およびbisectのパフォーマンスの比較をいくつか示します。時間(秒)は対数スケールです。

enter image description here

テスト用のコード

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()
151
xslittlegrass
def check_availability(element, collection: iter):
    return element in collection

使用法

check_availability('a', [1,2,3,4,'a','b','c'])

これが、選択された値が配列内にあるかどうかを知るための最も早い方法であると思います。

32
Tiago Moutinho

あなたのアイテムを set に入れることができます。集合検索は非常に効率的です。

試してください:

s = set(a)
if 7 in s:
  # do stuff

edit コメントでは、要素のインデックスを取得したいと言っています。残念ながら、集合は要素位置の概念を持っていません。別の方法は、リストを事前にソートしてから、要素を見つける必要があるたびに バイナリ検索 を使用することです。

27
NPE
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()の部分を一度実行してから繰り返し使用することができます。状況が変わった場合は、あなたが何をしているのかについてもっと詳しく教えてください。

15
Winston Ewert

あなたのアプリケーションがブルームフィルタデータ構造の使用から利益を得るかもしれないように聞こえます。

一言で言えば、値がセット内に明確に存在していない場合、ブルームフィルタルックアップは非常に迅速にあなたに伝えることができます。そうでなければ、リストの中にある可能性がある値のインデックスを得るために、より遅いルックアップをすることができます。そのため、アプリケーションが「見つかりません」という結果よりもはるかに頻繁に「見つからない」という結果を得る傾向がある場合は、ブルームフィルタを追加することで速度が向上する可能性があります。

詳細については、ウィキペディアでブルームフィルタの仕組みの概要を説明しています。また、 "pythonブルームフィルタライブラリ"をWebで検索すると、少なくとも2つの便利な実装が提供されます。

6
matt2000

in演算子は等価性(==)だけでなく同一性(is)もテストします。insの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()を持つinsのlistロジックは次のようになります。

any(element is target or element == target for element in lst)

ただし、これはEdgeのケースであることを強調しておく必要があります。大多数のケースでは、in演算子は非常に最適化されており、もちろんlistまたはsetを使用する必要があります。

4
Chris_Rands

これはコードではなく、非常に高速な検索のためのアルゴリズムです。

あなたのリストとあなたが探している値がすべて数字であれば、これはかなり簡単です。文字列の場合:一番下を見てください:

  • - リストの長さを "n"にします
  • - オプションのステップ:要素のインデックスが必要な場合:要素の現在のインデックス(0からn-1)を持つリストに2番目の列を追加します - 後で見ます
  • リストまたはそのコピーを注文する(.sort())
  • ループスルー:
    • あなたの番号をリストのn/2番目の要素と比較してください
      • 大きい場合は、インデックスn/2-nの間で再度ループします。
      • 小さい場合は、インデックス0〜n/2の間で再度ループします。
      • 同じなら:あなたはそれを見つけました
  • リストが見つかるまで、または2つの数字しか表示されなくなるまで(探しているものの上下に)リストを絞り込んでください。
  • これは、 内の任意の要素を1.000.000のリストに対して最大19ステップで検索します (正確にはlog(2)n)

番号の元の位置も必要な場合は、2番目のインデックス列で探します。

あなたのリストが数字で作られていない場合でも、この方法はうまくいき最速ですが、文字列を比較/順序付けできる関数を定義する必要があるかもしれません。

もちろん、これにはsorted()メソッドを投資する必要がありますが、チェックのために同じリストを再利用し続ける場合は、それだけの価値があります。

2
Adam

または__contains__を使用してください。

sequence.__contains__(value)

デモ:

>>> l=[1,2,3]
>>> l.__contains__(3)
True
>>> 
2
U9-Forward

@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にないことを確認する必要があります。

1
user3897315

私にとっては、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
1
Tabin1000
present = False
searchItem = 'd'
myList = ['a', 'b', 'c', 'd', 'e']
if searchItem in myList:
   present = True
   print('present = ', present)
else:
   print('present = ', present)
0
Hafizur Rahman

積がkに等しい配列に2つの要素が存在するかどうかをチェックするコード。

n = len(arr1)
for i in arr1:
    if k%i==0:
        print(i)
0
ravi tanwar