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

时间:2013-01-16 06:37:23

标签: 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:
            return True
    return False

有更优雅的方式吗?

6 个答案:

答案 0 :(得分:12)

使用以下内容检查ab的元素:

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)

答案 1 :(得分:7)

这有效:

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

答案 2 :(得分:3)

您无需将list转换为set,只需转换为{1}。我认为跳过不必要的转换会使其更具可读性和优雅性。

所以,要么:

set(a).intersection(b)

或者:

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

后者具有短路的优势,只要找到一个匹配,并更好地表达逻辑,并返回TrueFalse而不是非假的或假的{{1如果这困扰你,那么它是两行而不是一行。我不知道这个优势是否取消了将循环置于生成器表达式而不是C函数内的成本。

这个小set的性能结果几乎毫无意义,所以让我们试试这个:

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 除最后需要之外的所有成本,并比较三个Python版本中的相同测试(Apple stock CPython 2.7.2,python .org CPython 3.3.0,Homebrew PyPy 1.9.0 / 2.7.2,所有64位Mac版本):

set(a)

现在我想起来,这完全有道理。很早就发生碰撞的可能性非常高,因此将整个事物转换成一套的成本占主导地位。

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

                  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 的费用 - 如果其中任何一个列表值得做,更不用说两者了!

所以,让我们尝试一下 no 匹配的情况:

set

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

那么哪一个最好?

显然,如果你期望发生很多碰撞,你想尽可能避免制作套装 - 但是如果你预计碰撞很少,你想要制作至少一套。如果你不知道,我认为最安全的赌注是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 - 最糟糕的是它不到最好的3倍,如果碰撞率很高,它会快得多。但你可以看一下这些数字并亲自看看。

或者,当然,更好的是,将它们全部与您期望遇到的真实测试数据进行对比。

答案 3 :(得分:1)

def elm_exists(lista, listb):
    return bool(set(lista) & set(listb))

对于所有非空容器,bool函数将返回True,对于空容器,False将返回&。集合交集(set(lista).intersection(listb))将返回两组的一组公共元素。请注意,集合将删除任何重复项。

或者,您可以在bool函数中使用{{1}}。

答案 4 :(得分:0)

>>> y = [1,23,3]
>>> z = [3,432]
>>> (3 in y) and (3 in z)
True

答案 5 :(得分:0)

这是另一种解决方案,

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