Python:リストから検索


586

私はこれに遭遇しました:

item = someSortOfSelection()
if item in myList:
    doMySpecialFunction(item)

しかし、リストで認識されなかったかのように(文字列のリストの場合)、すべてのアイテムで機能しない場合があります。

これはリスト内のアイテムを見つける最も「パイソン的な」方法if x in l:ですか?


3
これは完全に問題なく、itemが内の要素の1つと等しい場合に機能しますmyList
Niklas B.

1
それは物事を行うための良い方法だったということですか?私のいくつかの試行では、おそらく空白があり、ラインフィードが逆参照されていました...「リストで検索」を実装するための良い方法であることを確認したいだけです(一般的に)
Stephane Rolland

回答:


1174

最初の質問については、そのコードは完全に問題なくitem、内部の要素の1つと等しい場合に機能するはずmyListです。たぶん、アイテムの1つと正確に一致しない文字列を見つけようとするか、不正確さに悩まされている浮動小数点値を使用している可能性があります。

2番目の質問については、実際にリストで「検索」する方法はいくつかあります。

何かが入っているか確認する

これはあなたが説明するユースケースです:何かがリストの中にあるかどうかのチェック。ご存知のように、そのためにin演算子を使用できます。

3 in [1, 2, 3] # => True

コレクションのフィルタリング

つまり、特定の条件を満たすシーケンス内のすべての要素を見つけることです。そのために、リスト内包表記またはジェネレータ式を使用できます。

matches = [x for x in lst if fulfills_some_condition(x)]
matches = (x for x in lst if x > 6)

後者は、あなたがそれを繰り返したときにのみ構築される一種の怠惰なリストとして想像できるジェネレータを返します。ちなみに、最初のものはまったく同じです

matches = filter(fulfills_some_condition, lst)

Python 2の場合。ここでは、高次関数が機能しているのがわかります。Python 3ではfilter、リストは返されませんが、ジェネレーターのようなオブジェクトが返されます。

最初の出現を見つける

条件に一致する最初のものだけが必要な場合(ただし、それがまだ何であるかはわかりません)、forループを使用することで問題はありません(おそらくelseあまり知られていない節も使用します)。あなたも使うことができます

next(x for x in lst if ...)

最初の一致を返すか、StopIteration見つからない場合はaを発生させます。別の方法として、

next((x for x in lst if ...), [default value])

アイテムの場所を見つける

リストのindex場合、特定の要素がリストのどこにあるかを知りたい場合に役立つメソッドもあります。

[1,2,3].index(2) # => 1
[1,2,3].index(4) # => ValueError

ただし、重複がある場合は、.index常に最低のインデックスを返すことに注意してください:......

[1,2,3,2].index(2) # => 1

重複があり、すべてのインデックスが必要な場合は、enumerate()代わりに使用できます。

[i for i,x in enumerate([1,2,3,2]) if x==2] # => [1, 3]

10
Stephane:言い換えると、組み込み関数でif x in listないと不満を言うのではありません。彼らは、特定の条件に一致するリスト内の何かの最初の発生を見つける明確な方法がないという事実に不満を述べています。しかし、私の回答で述べたように、next()そのために(ab)使用できます。
Niklas B.

3
@Stephane:2番目のものはタプルを生成しませんが、ジェネレーター(基本的にはまだ作成されていないリストです)を生成します。結果を1回だけ使用する場合は、通常、ジェネレーターを使用することをお勧めします。ただし、作成したコレクションを後で数回使用する場合は、最初に明示的なリストを作成することをお勧めします。私の更新を見てください、それは今やや構造化されています:)
Niklas B.

26
「最初の発生を見つける」例は黄金です。[list comprehension...][0]アプローチよりもパイソンのような感じ
acjay 2013

4
私はPythonの「機能的」機能にますます失望しています。haskellでは、Data.Listモジュールにfind関数があり、まさにそれを行っています。しかし、Pythonではそうではありませんし、ライブラリにするのはとても小さいので、同じロジックを何度も再実装する必要があります。なんという無駄...
user1685095

3
によって受け入れられたように機能するindex()呼び出されたクワーグがあったら、それは素晴らしいでしょう。例:。keykeymax()index(list, key=is_prime)
Curt

189

1つの要素を検索Noneする場合、またはでデフォルトを使用nextするStopIteration場合、項目がリストに見つからなかった場合は発生しません。

first_or_default = next((x for x in lst if ...), None)

1
next最初のパラメーターとしてイテレーターを取り、リスト/タプルはイテレーターではありません。したがって、first_or_default = next(iter([x for x in lst if ...]), None)
docs.python.org /

7
@Devy:右だが、(x for x in lst if ...)リストの上に発電機であるlstあるイテレータ)。その場合はnext(iter([x for x in lst if ...]), None)、リストを作成する必要がありますが[x for x in lst if ...]、これははるかにコストのかかる操作になります。
Erlend Graff

1
ここには、検索機能を定義するための抽象化があります。のブール式をifラムダにカプセル化するだけで、find(fn,list)ジェネレータコードを難読化する代わりに、通常は記述できます。
セミオマント2017年

22

Niklas B.からの回答はかなり包括的ですが、リストからアイテムを見つけたい場合は、インデックスを取得すると便利なことがあります。

next((i for i, x in enumerate(lst) if [condition on x]), [default value])

11

最初の出現を見つける

そのためのレシピがありますitertools

def first_true(iterable, default=False, pred=None):
    """Returns the first true value in the iterable.

    If no true value is found, returns *default*

    If *pred* is not None, returns the first item
    for which pred(item) is true.

    """
    # first_true([a,b,c], x) --> a or b or c or x
    # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
    return next(filter(pred, iterable), default)

たとえば、次のコードはリストの最初の奇数を見つけます。

>>> first_true([2,3,4,5], None, lambda x: x%2==1)
3  

6

別の代替方法:を使用してアイテムがリストにあるかどうかを確認できますがif item in list:、これは注文O(n)です。アイテムの大きなリストを扱っていて、何かがリストのメンバーであるかどうかを知る必要がある場合は、最初にリストをセットに変換し、一定時間のセット検索を利用できます

my_set = set(my_list)
if item in my_set:  # much faster on average than using a list
    # do something

すべてのケースで正しいソリューションになるわけではありませんが、場合によっては、これによりパフォーマンスが向上することがあります。

でセットを作成することset(my_list)もO(n)であることに注意してください。これを1度だけ行う必要がある場合は、この方法で行う方が速くはありません。ただし、メンバーシップを繰り返し確認する必要がある場合は、最初のセットの作成後、すべてのルックアップでO(1)になります。


4

文字列のリストを操作するときに、2つの可能な検索の1つを使用することができます。

  1. リスト要素がアイテムと等しい場合( 'example'は['one'、 'example'、 'two']にあります):

    if item in your_list: some_function_on_true()

    'ex' in ['one'、 'ex'、 'two'] => True

    ['one'、 'ex'、 'two']の 'ex_1' => False

  2. リスト要素がアイテムのような場合( 'ex'は['one、' example '、' two ']または' example_1 'は[' one '、' example '、' two ']にあります):

    matches = [el for el in your_list if item in el]

    または

    matches = [el for el in your_list if el in item]

    次にlen(matches)、必要に応じてチェックするか読んでください。


3

定義と使用法

このcount()メソッドは、指定された値を持つ要素の数を返します。

構文

list.count(value)

例:

fruits = ['apple', 'banana', 'cherry']

x = fruits.count("cherry")

質問の例:

item = someSortOfSelection()

if myList.count(item) >= 1 :

    doMySpecialFunction(item)

2
これは非常に長いリストで効率的ですか?百万のリストを言って?
3kstc

1
私はわかりません !!!
josef

1

list.index(x)リストでxが見つかった場合にxのインデックスを返す#ValueErrorか、xが見つからなかった場合にメッセージを返すwhich を使用する代わりに、リストlist.count(x)でxの出現回数を返す(xが実際にリストにあることの検証)またはそれを使用できます。それ以外の場合は0を返します(xがない場合)。涼しい事はcount()、それはあなたのコードを壊すか、xが見つからなかったときのために例外をスローする必要はないということです


悪い点は、要素を数えることです。要素が見つかっても停止しません。そのパフォーマンスは、大きなリストの悪い
ジャン=フランソワ・ファーブル

1

値が収集物に一度存在するかどうかを確認する場合は、「in」演算子を使用するのが適切です。ただし、複数回チェックする場合は、bisectモジュールの使用をお勧めします。bisectモジュールを使用すると、データをソートする必要があることに注意してください。したがって、データを1回ソートすると、bisectを使用できます。私のマシンでbisectモジュールを使用すると、「in」演算子を使用するよりも約12倍高速です。

Python 3.8以上の構文を使用したコードの例を次に示します。

import bisect
from timeit import timeit

def bisect_search(container, value):
    return (
      (index := bisect.bisect_left(container, value)) < len(container) 
      and container[index] == value
    )

data = list(range(1000))
# value to search
true_value = 666
false_value = 66666

# times to test
ttt = 1000

print(f"{bisect_search(data, true_value)=} {bisect_search(data, false_value)=}")

t1 = timeit(lambda: true_value in data, number=ttt)
t2 = timeit(lambda: bisect_search(data, true_value), number=ttt)

print("Performance:", f"{t1=:.4f}, {t2=:.4f}, diffs {t1/t2=:.2f}")

出力:

bisect_search(data, true_value)=True bisect_search(data, false_value)=False
Performance: t1=0.0220, t2=0.0019, diffs t1/t2=11.71

0

文字列のリストの項目に追加の/不要なホワイトスペースがないことを確認します。それが、アイテムが見つからないことの説明を妨げている可能性がある理由です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.