如何检查列表中是否包含以下项目之一?


220

我正在尝试寻找一种简短的方法来查看列表中是否包含以下任何项,但是我的第一次尝试不起作用。除了编写函数来完成此任务外,它还是检查多个项目之一是否在列表中的任何捷径。

>>> a = [2,3,4]
>>> print (1 or 2) in a
False
>>> print (2 or 1) in a
True

有趣的是,我检查了“和”的行为。a = [1, 2] b = [3, 5, 2, 6, 8, 9] c = [3, 5, 6, 8, 1, 9] print( (1 and 2) in b ,(2 and 1) in b ,(1 and 2) in c ,(2 and 1) in c, sep='\n')
对错对错

Answers:


266
>>> L1 = [2,3,4]
>>> L2 = [1,2]
>>> [i for i in L1 if i in L2]
[2]


>>> S1 = set(L1)
>>> S2 = set(L2)
>>> S1.intersection(S2)
set([2])

空列表和空集都为False,因此您可以将值直接用作真值。


6
相交的想法给了我这个主意。返回len(set(a).intersection(set(b)))
Deon

13
FWIW-我进行了速度比较,这里提供的第一个解决方案是禁食。
jackiekazil 2012年

2
使用发电机@ user89788的答案又是更快,因为any可以较早只要它找到一个返回True值-它并不必须先建立整个列表
Anentropic

如果列表中有重复项,则第二/套解决方案将不起作用(因为套组仅包含每个项目之一)。如果'L1 = [1,1,2,3]'和'L2 = [1,2,3]',则所有项都将相交。
donrondadon

我知道这已经快10年了,但是第一个解决方案似乎对我不起作用。我用L2中的数字替换了字符串,并且出现以下错误:TypeError:'in <string>'需要将字符串作为左操作数,而不是列表
roastbeeef19年

227

啊,托比亚斯你击败了我。我正在考虑您的解决方案的这种细微变化:

>>> a = [1,2,3,4]
>>> b = [2,7]
>>> print(any(x in a for x in b))
True

5
我知道这是一个很老的答案,但是如果一个列表很长而另一个列表很短,是否有顺序可以产生更快的性能?(即x in long for x in shortvs x in short for x in long
卢克·萨潘

11
@LukeSapan:你是对的。可以通过“为min(a,b,key = len)中的x打印any(max(a,b,key = len)中的x)”获得该顺序。它使用x in long表示x简称。
核人2014年

2
这是最好的答案,因为它使用生成器,并在找到匹配项后立即返回(就像其他人所说的,只是不在此答案上!)。
dotcomly

4
@Nuclearman,请注意:如果两个列表ab的长度相同,则max和min将返回最左侧的列表,这将使any()通话在双方的同一列表上进行。如果您绝对需要检查长度,请在第二个调用中反转列表的顺序:any(x in max(a, b, key=len) for x in (b, a, key=len))
诺亚·鲍嘉

3
@NoahBogart您是正确的,该解决方案似乎和其他解决方案一样好。我还假定您的意思是:(any(x in max(a, b, key=len) for x in min(b, a, key=len))错过了分钟)。
核弹手

29

也许有点懒:

a = [1,2,3,4]
b = [2,7]

print any((True for x in a if x in b))

1
它几乎与我发布的相同。
BastienLéonard09年

5
@BastienLéonard...除了它要快得多,因为它使用生成器,因此any可以提早返回,而您的版本必须先理解才能构建整个列表,然后any才能使用它。@ user89788的答案稍好一点,因为不需要双括号
Anentropic 2014年

17

考虑一下代码实际上是怎么说的!

>>> (1 or 2)
1
>>> (2 or 1)
2

那可能可以解释一下。:) Python显然实现了“惰性”,这不足为奇。它执行如下操作:

def or(x, y):
    if x: return x
    if y: return y
    return False

在第一个示例中,x == 1y == 2。在第二个示例中,反之亦然。这就是为什么它根据它们的顺序返回不同的值的原因。


16
a = {2,3,4}
if {1,2} & a:
    pass

代码高尔夫球版。如果有必要,请考虑使用集合。我发现这比列表理解更具可读性。


12

1行,没有列表推导。

>>> any(map(lambda each: each in [2,3,4], [1,2]))
True
>>> any(map(lambda each: each in [2,3,4], [1,5]))
False
>>> any(map(lambda each: each in [2,3,4], [2,4]))
True


6

在python 3中,我们可以开始使用unpack星号。给出两个列表:

bool(len({*a} & {*b}))

编辑:纳入alkanen的建议


1
@Anthony,它将创建一个包含a中的元素的集合,以及另一个包含b中的元素的集合,然后找到这些集合之间的交集(共享元素),如果有任何此类元素为真,则any()返回true。如果唯一的共享元素是虚假的(例如数字0),则该解决方案将不起作用。使用len()比使用any()更好
alkanen

1
@alkanen好电话
Daniel Braun

为什么不使用设置功能?
Alex78191 '19

5

当您认为“检查b中是否存在a”时,请考虑哈希(在这种情况下为set)。最快的方法是散列要检查的列表,然后检查其中的每个项目。

这就是Joe Koberg的答案之所以如此之快的原因:检查集合交集非常快。

但是,当您没有大量数据时,进行设置可能会浪费时间。因此,您可以建立一组列表,然后仅检查每个项目:

tocheck = [1,2] # items to check
a = [2,3,4] # the list

a = set(a) # convert to set (O(len(a)))
print [i for i in tocheck if i in a] # check items (O(len(tocheck)))

当您要检查的项目数量很少时,差异可以忽略不计。但是要检查一大堆数字...

测试:

from timeit import timeit

methods = ['''tocheck = [1,2] # items to check
a = [2,3,4] # the list
a = set(a) # convert to set (O(n))
[i for i in tocheck if i in a] # check items (O(m))''',

'''L1 = [2,3,4]
L2 = [1,2]
[i for i in L1 if i in L2]''',

'''S1 = set([2,3,4])
S2 = set([1,2])
S1.intersection(S2)''',

'''a = [1,2]
b = [2,3,4]
any(x in a for x in b)''']

for method in methods:
    print timeit(method, number=10000)

print

methods = ['''tocheck = range(200,300) # items to check
a = range(2, 10000) # the list
a = set(a) # convert to set (O(n))
[i for i in tocheck if i in a] # check items (O(m))''',

'''L1 = range(2, 10000)
L2 = range(200,300)
[i for i in L1 if i in L2]''',

'''S1 = set(range(2, 10000))
S2 = set(range(200,300))
S1.intersection(S2)''',

'''a = range(200,300)
b = range(2, 10000)
any(x in a for x in b)''']

for method in methods:
    print timeit(method, number=1000)

速度:

M1: 0.0170331001282 # make one set
M2: 0.0164539813995 # list comprehension
M3: 0.0286040306091 # set intersection
M4: 0.0305438041687 # any

M1: 0.49850320816 # make one set
M2: 25.2735087872 # list comprehension
M3: 0.466138124466 # set intersection
M4: 0.668627977371 # any

一贯快速的方法是制作一组(列表中的),但是交集在大型数据集上的效果最好!


3

在某些情况下(例如,唯一列表元素),可以使用设置操作。

>>> a=[2,3,4]
>>> set(a) - set([2,3]) != set(a)
True
>>> 

或者,使用set.isdisjoint()

>>> not set(a).isdisjoint(set([2,3]))
True
>>> not set(a).isdisjoint(set([5,6]))
False
>>> 

2

这将在一行中完成。

>>> a=[2,3,4]
>>> b=[1,2]
>>> bool(sum(map(lambda x: x in b, a)))
True

我在这里没有得到True >>>打印a [2,3,4] >>>打印b [2,7] >>> reduce(lambda x,y:x in b,a)False
Deon

是的 你是对的。reduce()并没有像我想的那样处理布尔值。我上面写的修订版适用于这种情况。
克里斯·厄普彻奇2009年

2

我收集了其他答案和评论中提到的几种解决方案,然后进行了速度测试。not set(a).isdisjoint(b)原来是最快的,结果还没减慢多少False

每个三次运行的测试的可能的配置的一个小样本ab。时间以微秒为单位。

Any with generator and max
        2.093 1.997 7.879
Any with generator
        0.907 0.692 2.337
Any with list
        1.294 1.452 2.137
True in list
        1.219 1.348 2.148
Set with &
        1.364 1.749 1.412
Set intersection explcit set(b)
        1.424 1.787 1.517
Set intersection implicit set(b)
        0.964 1.298 0.976
Set isdisjoint explicit set(b)
        1.062 1.094 1.241
Set isdisjoint implicit set(b)
        0.622 0.621 0.753

import timeit

def printtimes(t):
    print '{:.3f}'.format(t/10.0),

setup1 = 'a = range(10); b = range(9,15)'
setup2 = 'a = range(10); b = range(10)'
setup3 = 'a = range(10); b = range(10,20)'

print 'Any with generator and max\n\t',
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup3).timeit(10000000))
print

print 'Any with generator\n\t',
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup3).timeit(10000000))
print

print 'Any with list\n\t',
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup3).timeit(10000000))
print

print 'True in list\n\t',
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup3).timeit(10000000))
print

print 'Set with &\n\t',
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup3).timeit(10000000))
print

print 'Set intersection explcit set(b)\n\t',
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup3).timeit(10000000))
print

print 'Set intersection implicit set(b)\n\t',
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup3).timeit(10000000))
print

print 'Set isdisjoint explicit set(b)\n\t',
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup3).timeit(10000000))
print

print 'Set isdisjoint implicit set(b)\n\t',
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup3).timeit(10000000))
print

0

我不得不说,我的处境可能不是您想要的,但它可能为您的思考提供了另一种选择。

我已经尝试了set()和any()方法,但是仍然存在速度问题。因此,我记得Raymond Hettinger所说的python中的所有内容都是字典,并尽可能使用dict。这就是我尝试过的。

我使用带有int的defaultdict表示否定结果,并将第一个列表中的项目用作第二个列表的键(转换为defaultdict)。因为您可以使用dict进行即时查找,所以您会立即知道默认dict中是否存在该项目。我知道您并不总是可以更改第二个列表的数据结构,但是如果您能够从一开始就进行更改,那么它会更快。您可能需要将list2(较大的列表)转换为defaultdict,其中key是您要从小列表中检查的潜在值,值是1(命中)或0(无命中,默认)。

from collections import defaultdict
already_indexed = defaultdict(int)

def check_exist(small_list, default_list):
    for item in small_list:
        if default_list[item] == 1:
            return True
    return False

if check_exist(small_list, already_indexed):
    continue
else:
    for x in small_list:
        already_indexed[x] = 1

-4

简单。

_new_list = []
for item in a:
    if item in b:
        _new_list.append(item)
    else:
        pass

1
这不能回答问题。OP想要知道list中 是否有任何值a在list中b
That1Guy 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.