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

Python 比较两个列表中是否存在元素,python,list,Python,List,检查两个给定列表中是否存在元素的最简单、最优雅的方法是什么。例如,我有两个列表,如下所示 >>>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: retur

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

>>>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

有更优雅的方法吗?

用以下方法检查
a
b
的元素:

set(a).intersection(b)
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
例如:

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
此外:

因此,请使用
设置(a)。交叉点(b)

此功能:

>>> l1,l2=['a', 'b', 'g', 'r'], ['e', 'g', 'l', 1, 'w']
>>> list(set(l1)&set(l2))
['g']
bool
函数将为所有非空容器返回
True
,为空容器返回
False
。集合交集(
&
)将返回两个集合的一组公共元素。请注意,集合将删除任何重复项


或者,您可以在
bool
函数中使用
set(lista).intersection(listb)

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

>>> y = [1,23,3]
>>> z = [3,432]
>>> (3 in y) and (3 in z)
True
因此,要么:

set(a).intersection(b)
或:

后者的优点是在找到一个匹配项时立即短路,更好地表达逻辑,并返回
True
False
,而不是非False或False
集,但如果您感到不安,它是两行而不是一行。我不知道这一优势是否抵消了将循环放在生成器表达式中而不是放在C函数中的成本

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

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)
的成本,并比较三个Python版本(苹果股票CPython 2.7.2、Python.org CPython 3.3.0、自制PyPy 1.9.0/2.7.2、所有64位Mac版本)的相同测试:

现在我想起来了,这完全有道理。很早就发生碰撞的几率非常高,因此将整个事件转换为集合的成本占主导地位

这意味着我们需要一个新的测试,有10000个唯一的值。让我们用以下方法重复测试:

set(a).intersection(b)
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个随机排列的元素,你需要在每一个元素中走多远?还不足以让
设置的成本
-证明这两个列表中的任何一个值得一做,更不用说两个了

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

我不知道PyPy上一个怎么跑得这么快,但除此之外,这里没有什么令人惊讶的

那么,哪一个最好

显然,如果您预期会发生大量碰撞,则希望尽可能避免生成集合,但如果您预期会发生少量碰撞,则希望至少生成一个集合。如果你不知道的话,我认为最安全的赌注是
any(genexp)
——最坏的情况是比最好的情况差不到3倍,而且如果碰撞率很高的话,速度会快得多。但是你可以看看这些数字,自己看看


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

这是另一种解决方案

>>> c = [filter(lambda x: x in b, sublist) for sublist in a]
>>> filter (lambda a: a != '', c)
['g']

每个列表中的元素是否唯一?如果是这样的话,您只需使用
集合
就可以做到这一点。是的,列表中的元素是唯一的。@迈克:等等……为什么即使元素不是唯一的,您也不能使用集合呢?您会丢失元素多次存在的信息,但如果您只关心该元素是否存在,则不需要该信息。(如果你这样做了,你总是可以用
计数器
而不是
集合
来保留它。)@JonClements,谢谢,非常优雅!我不确定用这么短的列表来计时结果是否有多大意义。如果你只是将长度减少到3和4,而不是4和5,这就足以使
列表
设置
版本更快,至少在我的计算机上是这样,但我不认为这实际上意味着做
O(NM)
算法比和
O(N+M)
算法更好!请参阅我编辑的答案。这取决于数据集的大小和碰撞的频率。这本应该是显而易见的…但直到我试图弄明白这些数字。无论如何,在大多数情况下,这两个版本和我在
集合(a)
上的生成器表达式都足够快,OP最初的问题是关于优雅而不是性能,因此…我认为
交叉点
&
更优雅和可读,而
any…in…for
表达式更是如此,但是交集内的
set(listb)
是冗余的,因为
交集将任何iterable(s)作为参数,这里也不需要
len
,因为
bool(len(x))
保证返回与
bool(x)
相同的东西,更简单、更高效。感谢JonClements和abarnert,改变是疯狂的工作(和+1),但OP要求的是“最简单”和“最优雅”,而不是最快的!作为一个Numpy用户,我想到的第一个函数是
np.any(np.in1d(x,y))
。我很想看看这两者的对比。然而,你的证据支持一个一般规则。。。转换数据的成本通常超过测试的成本,除非数据集非常大。@cxrogers:我的答案的开头是关于“可读性”和“优雅性”,这就是原始版本中的全部内容,我认为这仍然是答案中最重要的部分。在不可避免的关于什么是最快的争论之后,所有其他的东西都被添加了;它比重要部分长得多的唯一原因是,您可以保持简单,但不能保持性能测试的简单。
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
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
>>> c = [filter(lambda x: x in b, sublist) for sublist in a]
>>> filter (lambda a: a != '', c)
['g']