Pythonでタプルのリストを検索する方法


90

だから私はこのようなタプルのリストを持っています:

[(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]

数値が何かと等しいタプルのこのリストが必要です。

だから私がsearch(53)それをするならそれはのインデックス値を返すでしょう2

これを行う簡単な方法はありますか?

回答:


94
[i for i, v in enumerate(L) if v[0] == 53]

68
説明していただけますか?
シャッテン2013年

17
単語で説明:Lの列挙リスト内の各i、v(iが列挙リスト内の要素の位置、vが元のタプルになる)について、タプルの最初の要素が53かどうかを確認し、そうであれば、コードの結果を追加する新しく作成されたリストの「for」の前、ここ:i。my_function(i、v)またはさらに別のリスト内包である場合もあります。タプルのリストには、最初の値が53のタプルが1つしかないため、要素が1つあるリストを取得します。
djangonaut 2014

6
[v [0] == 53] .pop()の場合、[i for i、v in enumerate(L)]を追加してint値にします。
alemol


47

tl; dr

ジェネレータ式は、おそらくあなたの問題のほとんどのパフォーマンスとシンプルなソリューションです。

l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]

result = next((i for i, v in enumerate(l) if v[0] == 53), None)
# 2

説明

リスト内包表記を使用して、この質問に対する簡単な解決策を提供するいくつかの回答があります。これらの答えは完全に正しいですが、最適ではありません。ユースケースによっては、いくつかの簡単な変更を加えることで大きなメリットが得られる場合があります。

このユースケースでリスト内包表記を使用する場合に発生する主な問題は、リスト全体が処理されることですが、1つの要素しか検索しません

Pythonは、ここで理想的な単純な構成を提供します。これはジェネレータ式と呼ばれます。次に例を示します。

# Our input list, same as before
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]

# Call next on our generator expression.
next((i for i, v in enumerate(l) if v[0] == 53), None)

このメソッドは基本的に、ささいな例のリスト内包と同じように機能することが期待できますが、より大きなデータセットで作業している場合はどうでしょうか。ここで、ジェネレーターメソッドを使用する利点が発揮されます。新しいリストを作成するのではなく、既存のリストを反復可能として使用し、next()し、ジェネレーターから最初のアイテムを取得するためにします。

これらのメソッドが一部の大きなデータセットで異なる動作をする様子を見てみましょう。これらは、10000000 + 1要素で構成される大きなリストであり、ターゲットは最初(最高)または最後(最悪)です。これらのリストの両方が、次のリスト内包表記を使用して同等に機能することを確認できます。

内包表記

"最悪の場合"

worst_case = ([(False, 'F')] * 10000000) + [(True, 'T')]
print [i for i, v in enumerate(worst_case) if v[0] is True]

# [10000000]
#          2 function calls in 3.885 seconds
#
#    Ordered by: standard name
#
#    ncalls  tottime  percall  cumtime  percall filename:lineno(function)
#         1    3.885    3.885    3.885    3.885 so_lc.py:1(<module>)
#         1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

"最良の場合"

best_case = [(True, 'T')] + ([(False, 'F')] * 10000000)
print [i for i, v in enumerate(best_case) if v[0] is True]

# [0]
#          2 function calls in 3.864 seconds
#
#    Ordered by: standard name
#
#    ncalls  tottime  percall  cumtime  percall filename:lineno(function)
#         1    3.864    3.864    3.864    3.864 so_lc.py:1(<module>)
#         1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

ジェネレータ式

ジェネレーターの私の仮説は次のとおりです。ジェネレーターは、最良の場合に大幅にパフォーマンスが向上することがわかりますが、最悪の場合も同様です。このパフォーマンスの向上は、主にジェネレータが遅延評価されるため、値を生成するために必要なものだけを計算するためです。

最悪の場合

# 10000000
#          5 function calls in 1.733 seconds
#
#    Ordered by: standard name
#
#    ncalls  tottime  percall  cumtime  percall filename:lineno(function)
#         2    1.455    0.727    1.455    0.727 so_lc.py:10(<genexpr>)
#         1    0.278    0.278    1.733    1.733 so_lc.py:9(<module>)
#         1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
#         1    0.000    0.000    1.455    1.455 {next}

最良の場合

best_case  = [(True, 'T')] + ([(False, 'F')] * 10000000)
print next((i for i, v in enumerate(best_case) if v[0] == True), None)

# 0
#          5 function calls in 0.316 seconds
#
#    Ordered by: standard name
#
#    ncalls  tottime  percall  cumtime  percall filename:lineno(function)
#         1    0.316    0.316    0.316    0.316 so_lc.py:6(<module>)
#         2    0.000    0.000    0.000    0.000 so_lc.py:7(<genexpr>)
#         1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
#         1    0.000    0.000    0.000    0.000 {next}

何?!最高のケースが吹き飛ばされるはリストの内包をが、私は最悪のケースがリストの内包をその程度まで上回るとは思っていませんでした。どう?率直に言って、私はそれ以上の調査なしには推測しかできませんでした。

これらすべてを詳細に検討します。ここでは、非常に基本的なテストのみを行って、堅牢なプロファイリングを実行していません。これは、ジェネレータ式がこのタイプのリスト検索でよりパフォーマンスが高いことを理解するのに十分なはずです。

これはすべて基本的な組み込みPythonであることに注意してください。何もインポートしたり、ライブラリを使用したりする必要はありません。

私は最初に、Peter NorvigとのUdacity cs212コースで検索するためのこのテクニックを見ました。


2
興味深いことに、私はテストして本当に速いことがわかりました
Grijesh Chauhan 2014

3
これは受け入れられる答えになるはずです。ジェネレータ式は、実行時に出力シーケンス全体を具体化するのではなく、式から一度に1つの項目を生成するイテレータに評価します。
BoltzmannBrain

2
これは素晴らしく、私の場合はリストの理解よりはるかに速いです、ありがとう!
mindm49907

29

あなたのタプルは基本的にキーと値のペア、dictつまりpythonです--so:

l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
val = dict(l)[53]

編集-ああ、あなたは(53、 "xuxa")のインデックス値が欲しいと言います。これが本当に必要な場合は、元のリストを反復処理するか、おそらくより複雑な辞書を作成する必要があります。

d = dict((n,i) for (i,n) in enumerate(e[0] for e in l))
idx = d[53]

2
OPが実際に要求したものを無視した場合、私はあなたの最初の答えが「Pythonでタプルのリストを検索する方法」への最良の答えだと思います
Rick Westera

あなたの最初の答えは私の目的に役立ちました。ただし、アイテムが辞書にない場合は、.get()を使用することをお勧めします。 l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")] val = dict(l).get(53)
user1503941 2015年

12

うーん...まあ、頭に浮かぶ簡単な方法は、それを辞書に変換することです

d = dict(thelist)

とアクセスd[53]

編集:おっと、あなたの質問を初めて読み間違えました。特定の数値が格納されているインデックスを実際に取得したいようです。その場合は、

dict((t[0], i) for i, t in enumerate(thelist))

単純な古いdict変換の代わりに。次にd[53]2になります。


6

リストが長く、数値が繰り返される可能性がある場合は、PythonのsortedcontainersモジュールのSortedListタイプの使用を検討してください。SortedListタイプは、番号順にタプルを自動的に維持し、高速検索を可能にします。

例えば:

from sortedcontainers import SortedList
sl = SortedList([(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")])

# Get the index of 53:

index = sl.bisect((53,))

# With the index, get the tuple:

tup = sl[index]

これは、バイナリ検索を行うことで、リスト内包候補よりもはるかに高速に機能します。辞書の提案はより速くなりますが、異なる文字列で重複する数値が存在する可能性がある場合は機能しません。

異なる文字列の重複する数値がある場合は、もう1つの手順を実行する必要があります。

end = sl.bisect((53 + 1,))

results = sl[index:end]

54を2等分することで、スライスの終了インデックスがわかります。これは、受け入れられた回答と比較して、長いリストではかなり高速になります。



-1

[v == ' デリシア 'の場合、lのk、vのk ]

ここでlはタプルのリストです-[(1、 "juca")、(22、 "james")、(53、 "xuxa")、(44、 "delicia")]

そして、それをdictに変換する代わりに、llist内包表記を使用しています。

*Key* in Key,Value in list, where value = **delicia**


はい、そうです。@cosmoonotありがとうございます。
Mantej Singh 2017

ここで、lはタプルのリストです-[(1、 "juca")、(22、 "james")、(53、 "xuxa")、(44、 "delicia")]そして、dictに変換する代わりに、 llist内包表記を使用しています。` キー 値=キー、リストの値、でDELICIA `
Mantejシン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.