だから私はこのようなタプルのリストを持っています:
[(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
数値が何かと等しいタプルのこのリストが必要です。
だから私がsearch(53)
それをするならそれはのインデックス値を返すでしょう2
これを行う簡単な方法はありますか?
回答:
[i for i, v in enumerate(L) if v[0] == 53]
リスト内包表記を使用できます。
>>> a = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
>>> [x[0] for x in a]
[1, 22, 53, 44]
>>> [x[0] for x in a].index(53)
2
ジェネレータ式は、おそらくあなたの問題のほとんどのパフォーマンスとシンプルなソリューションです。
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コースで検索するためのこのテクニックを見ました。
あなたのタプルは基本的にキーと値のペア、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]
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")] val = dict(l).get(53)
リストが長く、数値が繰り返される可能性がある場合は、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等分することで、スライスの終了インデックスがわかります。これは、受け入れられた回答と比較して、長いリストではかなり高速になります。
[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**