list
両方を sに変換する必要はなくset
、1 つだけです。不要な変換をスキップすると、読みやすくエレガントになると思います。
したがって、次のいずれかです。
set(a).intersection(b)
または:
s = set(a)
any(e in s for e in b)
後者には、1 つの一致を見つけるとすぐに短絡し、ロジックをより適切に表現し、 non-falsey または falsey の代わりにTrue
orを返すという利点がありますが、それが気になる場合は、1 行ではなく 2 行になります。この利点が、ループを C 関数内ではなくジェネレーター式内に配置するコストを相殺するかどうかはわかりません。False
set
s がこれほど小さい場合のパフォーマンス結果list
はほとんど意味がないので、これを試してみましょう。
In [373]: a=[random.choice(string.ascii_lowercase) for _ in range(10000)]
In [374]: b=[random.choice(string.ascii_lowercase) for _ in range(10000)]
In [375]: %timeit(set(a))
10000 loops, best of 3: 180 us per loop
In [376]: s=set(a) # since all versions need to do this
In [391]: %timeit(s & set(b))
1000000 loops, best of 3: 178 us per loop
In [392]: %timeit(s.intersection(b))
1000000 loops, best of 3: 247 us per loop
In [393]: %timeit(discard(e in s for e in b))
1000000 loops, best of 3: 550 ns per loop
In [394]: %timeit(any(e in s for e in b))
1000000 loops, best of 3: 749 ns per loop
In [395]: %timeit(any(e in a for e in b))
1000000 loops, best of 3: 1.42 us per loop
数値をすべてナノ秒スケールに入れるにはset(a)
、最後の必要性を除くすべてのコストを追加し、3 つの Python バージョン (Apple ストック CPython 2.7.2、python.org CPython 3.3.0、Homebrew PyPy 1.9.0/2.7.2、すべての 64 ビット Mac ビルド):
CP272 CP330 PyPy
s & set(b) 358000 316000 180500
s.intersection(b) 427000 459000 180900
discard(genexp) 180550 157341 90094
any(genexp) 180749 157334 90208
any(list-genexp) 1420 686 960
今考えると、これは完全に理にかなっています。かなり早い段階で衝突が発生する可能性は非常に高いため、すべてをセットに変換するコストがすべてを支配します。
つまり、10000 個の一意の値を持つ新しいテストが必要です。これでテストを繰り返しましょう:
In [29]: a, b = list(range(10000)), list(range(10000))
In [30]: random.shuffle(a)
In [31]: random.shuffle(b)
CP272 CP330 PyPy
s & set(b) 1277000 1168000 1141000
s.intersection(b) 1165000 1117000 2520000
discard(genexp) 1699000 1271000 770000
any(genexp) 389800 344543 320807
any(list-genexp) 62000 10400 1520
これらはより合理的です。そして、それらはまだ理にかなっています。ランダムにシャッフルされた同じ 10000 個の要素を比較している場合、それぞれの要素をどこまで進める必要があるでしょうか? set
どちらかのリストを価値のあるものにするコストを作るには十分ではありません。
それでは、一致するものがない場合を試してみましょう。
In [43]: a=list(range(10000, 20000))
CP272 CP330 PyPy
s & set(b) 751000 770000 733000
s.intersection(b) 466000 530000 1920000
discard(genexp) 1246000 985000 749000
any(genexp) 1269000 966000 893000
any(list-genexp) 185000000 176000000 5870000
PyPy がどのようにして最後のものをこれほど速く実行したかはわかりませんが、それ以外は驚くことではありません。
それで、どれが一番いいですか?
多くの衝突が予想される場合は、可能な限りセットを作成したくないことは明らかですが、衝突がほとんどないと予想される場合は、少なくとも 1 つのセットを作成する必要があります。わからない場合は、最も安全な方法は、any(genexp)
最悪の場合でも最高の 3 倍未満であり、衝突率が高い可能性がある場合は、はるかに高速になることです。しかし、数字を見て自分の目で確かめることができます。
または、もちろん、遭遇することが予想される実際のテスト データに対してすべての時間を計測することをお勧めします。