10

要素が 2 つの指定されたリストに存在するかどうかを確認する最も簡単でエレガントな方法は何でしょうか。たとえば、次の 2 つのリストがあります。

>>>a, b = ['a', 'b', 'g', 'r'], ['e', 'g', 'l', 1, 'w']

上記のリストで、両方のリストに存在する要素があるかどうかを確認したいと思います。現在、私は次のようにやっています

def elm_exists(list_a, list_b):
    for elm in list_a:
        if elm in list_b:
            return True
    return False

これを行うためのよりエレガントな方法はありますか?

4

6 に答える 6

17

aこれでandの要素をチェックbします:

set(a).intersection(b)

例:

In [44]: nk=set(a).intersection(b)

In [45]: for x in a:
    ...:     if x in nk:
    ...:         print x, 'present in b'
    ...:     else:
    ...:         print x, 'absent in b'
    ...:         
a absent in b
b absent in b
g present in b
r absent in b

また:

In [47]: timeit(set(a) & set(b))
1000000 loops, best of 3: 940 ns per loop

In [48]: timeit(set(a).intersection(b))
1000000 loops, best of 3: 854 ns per loop

In [49]: timeit([x for x in a if x in b])
1000000 loops, best of 3: 1 us per loop

ですのでご利用set(a).intersection(b)ください。

于 2013-01-16T06:40:35.260 に答える
9

これは機能します:

>>> l1,l2=['a', 'b', 'g', 'r'], ['e', 'g', 'l', 1, 'w']
>>> list(set(l1)&set(l2))
['g']
于 2013-01-16T06:42:44.150 に答える
5

list両方を sに変換する必要はなくset、1 つだけです。不要な変換をスキップすると、読みやすくエレガントになると思います。

したがって、次のいずれかです。

set(a).intersection(b)

または:

s = set(a)
any(e in s for e in b)

後者には、1 つの一致を見つけるとすぐに短絡し、ロジックをより適切に表現し、 non-falsey または falsey の代わりにTrueorを返すという利点がありますが、それが気になる場合は、1 行ではなく 2 行になります。この利点が、ループを C 関数内ではなくジェネレーター式内に配置するコストを相殺するかどうかはわかりません。Falseset

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 倍未満であり、衝突率が高い可能性がある場合は、はるかに高速になることです。しかし、数字を見て自分の目で確かめることができます。

または、もちろん、遭遇することが予想される実際のテスト データに対してすべての時間を計測することをお勧めします。

于 2013-01-16T06:48:31.900 に答える
2
def elm_exists(lista, listb):
    return bool(set(lista) & set(listb))

このbool関数はTrue、空でないすべてのコンテナと空のコンテナに対して戻りFalseます。セット交差 ( &) は、2 つのセットの共通要素のセットを返します。セットは重複を削除することに注意してください。

set(lista).intersection(listb)または、関数で使用することもできますbool

于 2013-01-16T06:43:44.477 に答える
0
>>> y = [1,23,3]
>>> z = [3,432]
>>> (3 in y) and (3 in z)
True
于 2013-01-16T06:48:19.707 に答える
0

これは別の解決策であり、

>>> c = [filter(lambda x: x in b, sublist) for sublist in a]
>>> filter (lambda a: a != '', c)
['g']
于 2013-01-16T06:49:05.093 に答える