比较两个列表中是否存在元素

Amy*_*yth 8 python list

检查两个给定列表中是否存在元素的最简单,最优雅的方法是什么?例如,我有两个列表如下?

>>>a, b = ['a', 'b', 'g', 'r'], ['e', 'g', 'l', 1, 'w']
Run Code Online (Sandbox Code Playgroud)

现在在上面给出的列表中,我想检查两个列表中是否存在任何元素.目前我正在做如下

def elm_exists(list_a, list_b):
    for elm in list_a:
        if elm in list_b:
            return True
    return False
Run Code Online (Sandbox Code Playgroud)

有更优雅的方式吗?

nam*_*mit 13

检查a以及的元素b:

set(a).intersection(b)
Run Code Online (Sandbox Code Playgroud)

例:

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
Run Code Online (Sandbox Code Playgroud)

也:

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
Run Code Online (Sandbox Code Playgroud)

因此使用set(a).intersection(b).


the*_*olf 7

这有效:

>>> l1,l2=['a', 'b', 'g', 'r'], ['e', 'g', 'l', 1, 'w']
>>> list(set(l1)&set(l2))
['g']
Run Code Online (Sandbox Code Playgroud)


aba*_*ert 5

您不需要将两个lists 都转换为sets,只需一个即可。我认为跳过不必要的转换会使它更具可读性和优雅性。

\n\n

所以,要么:

\n\n
set(a).intersection(b)\n
Run Code Online (Sandbox Code Playgroud)\n\n

或者:

\n\n
s = set(a)\nany(e in s for e in b)\n
Run Code Online (Sandbox Code Playgroud)\n\n

后者的优点是一旦找到一个匹配就短路,并且可以更好地表达逻辑,并返回TrueorFalse而不是非 falsey 或 falsey set,但它是两行而不是一行,如果这让您烦恼的话。我不知道这个优点是否抵消了将循环放入生成器表达式而不是 C 函数中的成本。

\n\n

s 这么小的性能结果list几乎没有意义,所以让我们试试这个:

\n\n
In [373]: a=[random.choice(string.ascii_lowercase) for _ in range(10000)]\nIn [374]: b=[random.choice(string.ascii_lowercase) for _ in range(10000)]\nIn [375]: %timeit(set(a))\n10000 loops, best of 3: 180 us per loop\nIn [376]: s=set(a) # since all versions need to do this\nIn [391]: %timeit(s & set(b))\n1000000 loops, best of 3: 178 us per loop\nIn [392]: %timeit(s.intersection(b))\n1000000 loops, best of 3: 247 us per loop\nIn [393]: %timeit(discard(e in s for e in b))\n1000000 loops, best of 3: 550 ns per loop\nIn [394]: %timeit(any(e in s for e in b))\n1000000 loops, best of 3: 749 ns per loop\nIn [395]: %timeit(any(e in a for e in b))\n1000000 loops, best of 3: 1.42 us per loop\n
Run Code Online (Sandbox Code Playgroud)\n\n

要将所有数字都放在纳秒级别,请添加除set(a)最后一个需求之外的所有成本,并比较三个 Python 版本(Apple stock CPython 2.7.2、python.org CPython 3.3.0、Homebrew)的相同测试PyPy 1.9.0/2.7.2,所有 64 位 Mac 版本):

\n\n
                  CP272  CP330  PyPy\ns & set(b)        358000 316000 180500\ns.intersection(b) 427000 459000 180900\ndiscard(genexp)   180550 157341  90094\nany(genexp)       180749 157334  90208\nany(list-genexp)    1420    686    960\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在我想起来,这完全有道理。很早就发生碰撞的可能性非常高,因此将整个事物转换为集合的成本决定了一切。

\n\n

这意味着我们需要一个包含 10000 个唯一值的新测试。让我们重复一下测试:

\n\n
In [29]: a, b = list(range(10000)), list(range(10000))\nIn [30]: random.shuffle(a)\nIn [31]: random.shuffle(b)\n\n                  CP272  CP330  PyPy\ns & set(b)        1277000 1168000 1141000\ns.intersection(b) 1165000 1117000 2520000\ndiscard(genexp)   1699000 1271000  770000\nany(genexp)        389800  344543  320807\nany(list-genexp)    62000   10400    1520\n
Run Code Online (Sandbox Code Playgroud)\n\n

这些都比较合理。它们仍然有道理。如果您要比较随机洗牌的 10000 个相同元素,您需要对每个元素进行多深的比较?还不足以使set任何一个列表的验证成本值得做,更不用说两个列表了!

\n\n

那么,让我们尝试一下没有匹配项的情况:

\n\n
In [43]: a=list(range(10000, 20000))\n\n\n                  CP272     CP330     PyPy\ns & set(b)           751000    770000  733000\ns.intersection(b)    466000    530000 1920000\ndiscard(genexp)     1246000    985000  749000\nany(genexp)         1269000    966000  893000\nany(list-genexp)  185000000 176000000 5870000\n
Run Code Online (Sandbox Code Playgroud)\n\n

我不知道 PyPy 如何如此快地完成最后一个,但除此之外,这里没有什么惊喜。

\n\n

那么,哪一个最好呢?

\n\n

显然,如果您期望发生大量碰撞,则希望尽可能避免创建集合\xe2\x80\x94,但如果您期望发生很少的碰撞,则希望至少创建一组。如果你不知道,我认为最安全的选择是any(genexp)\xe2\x80\x94 在最坏的情况下它比最好的差不到 3 倍,如果有可能碰撞率很高,它会快很多。但你可以看看这些数字并亲自看看。

\n\n

或者,当然更好的是,根据您期望遇到的真实测试数据对它们进行计时。

\n