297

I'm trying to find a short way to see if any of the following items is in a list, but my first attempt does not work. Besides writing a function to accomplish this, is the any short way to check if one of multiple items is in a list.

>>> a = [2,3,4]
>>> print (1 or 2) in a
False
>>> print (2 or 1) in a
True
BartoszKP
  • 34,786
  • 15
  • 102
  • 130
Deon
  • 3,283
  • 3
  • 18
  • 8
  • See https://stackoverflow.com/questions/1342601 for testing more complex conditions rather than just membership in a list. See https://stackoverflow.com/questions/3931541 for testing if *all* values are in a list. – Karl Knechtel Aug 03 '22 at 00:05

15 Answers15

350
>>> 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])

Both empty lists and empty sets are False, so you can use the value directly as a truth value.

Joe Koberg
  • 25,416
  • 6
  • 48
  • 54
  • 8
    The intersection idea gave me this idea. return len(set(a).intersection(set(b))) – Deon Apr 11 '09 at 16:07
  • 25
    FWIW - I did a speed comparison, and the very first solution offered here was the fasted by far. – jackiekazil Jun 08 '12 at 15:43
  • 6
    @user89788's answer using a generator is much faster again, because `any` can return early as soon as it finds a `True` value - it doesn't have to build the whole list first – Anentropic Jan 29 '14 at 12:28
  • The second/sets solution won't work if you have duplicates in the list (as sets only contain one of each item). If `L1 = [1,1,2,3]' and 'L2 = [1,2,3]', all items will be seen to intersect. – ron_g Sep 21 '18 at 08:48
  • i know this is almost 10 years old, but the first solution doesnt seem to work for me. i've substituted the numbers in L2 for strings, and i'm getting the following error: TypeError: 'in ' requires string as left operand, not list – roastbeeef Jan 16 '19 at 12:21
  • @roastbeeef use : 'in list(foo)' instead of 'in foo' – Martial P Aug 04 '20 at 15:06
317

I was thinking of this slight variation on Tobias' solution:

>>> a = [1,2,3,4]
>>> b = [2,7]
>>> any(x in a for x in b)
True
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • 7
    I realize this is a very old answer, but if one list is very long and the other is short, is there an order that would yield faster performance? (i.e., `x in long for x in short` vs `x in short for x in long`) – Leah Sapan Feb 13 '14 at 18:08
  • 15
    @LukeSapan: You are correct. That order can be obtained via "print any(x in max(a,b,key=len) for x in min(a,b,key=len))". This uses x in long for x in short. – Nuclearman Apr 16 '14 at 23:33
  • 2
    This is the best answer because it uses a generator and will return as soon as a match is found (as others have said, just not on this answer!). – dotcomly Feb 20 '16 at 23:01
  • 8
    @Nuclearman, watch out: If the two lists `a` and `b` are the same length, max and min will return the left-most list, which makes the `any()` call operate over the same list on both sides. If you absolutely require checking for length, reverse the order of the lists in the second call: `any(x in max(a, b, key=len) for x in (b, a, key=len))`. – Noah Bogart Jan 31 '17 at 14:43
  • 6
    @NoahBogart You are correct and that solution seems as good as any. I also presume you meant: `any(x in max(a, b, key=len) for x in min(b, a, key=len))` (missed the min). – Nuclearman Jan 31 '17 at 19:45
35

Maybe a bit more lazy:

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

print any((True for x in a if x in b))
  • 1
    It's nearly the same as the one I posted. – Bastien Léonard Apr 11 '09 at 16:24
  • 11
    @BastienLéonard ...except it's much faster because it uses a generator and thus `any` can return early, whereas your version has to build the whole list from comprehension before `any` can use it. @user89788's answer is slightly better because the double parentheses are unnecessary – Anentropic Jan 29 '14 at 12:26
20

Think about what the code actually says!

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

That should probably explain it. :) Python apparently implements "lazy or", which should come as no surprise. It performs it something like this:

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

In the first example, x == 1 and y == 2. In the second example, it's vice versa. That's why it returns different values depending on the order of them.

Deniz Dogan
  • 25,711
  • 35
  • 110
  • 162
  • The `return y` at the end is not true. When all values are false, the last value is returned. It is more something like `if x: return x; else: return y`. – The_spider Jan 14 '23 at 19:24
19
a = {2,3,4}
if {1,2} & a:
    pass

Code golf version. Consider using a set if it makes sense to do so. I find this more readable than a list comprehension.

00500005
  • 3,727
  • 3
  • 31
  • 38
15

1 line without list comprehensions.

>>> 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
Himel Das
  • 1,148
  • 10
  • 13
12

Best I could come up with:

any([True for e in (1, 2) if e in a])
Bastien Léonard
  • 60,478
  • 20
  • 78
  • 95
7

In python 3 we can start make use of the unpack asterisk. Given two lists:

bool(len({*a} & {*b}))
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Daniel Braun
  • 2,452
  • 27
  • 25
  • 1
    @Anthony, it creates a set containing the elements in a, and another set containing the elements in b, then it finds the intersection (shared elements) between those sets and any() returns true if there are any such elements that are truthy. The solution won't work if the only shared element(s) are falsy (such as the number 0). It might be better to use len() than any() – alkanen Jan 08 '19 at 10:30
  • 1
    @alkanen Good call – Daniel Braun Jan 09 '19 at 12:17
  • why not to use set function? – Alex78191 Dec 15 '19 at 03:31
5

When you think "check to see if a in b", think hashes (in this case, sets). The fastest way is to hash the list you want to check, and then check each item in there.

This is why Joe Koberg's answer is fast: checking set intersection is very fast.

When you don't have a lot of data though, making sets can be a waste of time. So, you can make a set of the list and just check each item:

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

When the number of items you want to check is small, the difference can be negligible. But check lots of numbers against a large list...

tests:

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)

speeds:

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

The method that is consistently fast is to make one set (of the list), but the intersection works on large data sets the best!

dantiston
  • 5,161
  • 2
  • 26
  • 30
3

I collected several of the solutions mentioned in other answers and in comments, then ran a speed test. not set(a).isdisjoint(b) turned out the be the fastest, it also did not slowdown much when the result was False.

Each of the three runs tests a small sample of the possible configurations of a and b. The times are in microseconds.

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
chew socks
  • 1,406
  • 2
  • 17
  • 37
3

In some cases (e.g. unique list elements), set operations can be used.

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

Or, using set.isdisjoint(),

>>> not set(a).isdisjoint(set([2,3]))
True
>>> not set(a).isdisjoint(set([5,6]))
False
>>> 
gimel
  • 83,368
  • 10
  • 76
  • 104
1

This will do it in one line.

>>> a=[2,3,4]
>>> b=[1,2]
>>> bool(sum(map(lambda x: x in b, a)))
True
Chris Upchurch
  • 15,297
  • 6
  • 51
  • 66
  • I'm not getting a True here >>> print a [2, 3, 4] >>> print b [2, 7] >>> reduce(lambda x, y: x in b, a) False – Deon Apr 11 '09 at 16:10
  • Yep. You're right. reduce() wasn't quite handling boolean values the way I thought it would. The revised version I wrote above works for that case though. – Chris Upchurch Apr 11 '09 at 16:32
1

A lot of similar answers, but for me the simplest and cleanest way is just to logical AND two sets and return the result as a bool, and I think this one is not listed yet:

def check_for_matching_elements(list1, list2):
    return bool(set(list1) & set(list2))
gustavz
  • 2,964
  • 3
  • 25
  • 47
0

I have to say that my situation might not be what you are looking for, but it may provide an alternative to your thinking.

I have tried both the set() and any() method but still have problems with speed. So I remembered Raymond Hettinger said everything in python is a dictionary and use dict whenever you can. So that's what I tried.

I used a defaultdict with int to indicate negative results and used the item in the first list as the key for the second list (converted to defaultdict). Because you have instant lookup with dict, you know immediately whether that item exist in the defaultdict. I know you don't always get to change data structure for your second list, but if you are able to from the start, then it's much faster. You may have to convert list2 (larger list) to a defaultdict, where key is the potential value you want to check from small list, and value is either 1 (hit) or 0 (no hit, default).

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
yangliu2
  • 391
  • 4
  • 15
-6

Simple.

_new_list = []
for item in a:
    if item in b:
        _new_list.append(item)
    else:
        pass
PyGuy
  • 49
  • 3
  • 1
    This does not answer the question. OP wants to know if *any value from list* `a` is in list `b`. – That1Guy May 19 '15 at 17:57
  • Plus it's very slow compared to a comprehension. And eats RAM like stupid if you've many items; in any (or at least most) case, it should be better to use a generator instead. – rautamiekka Mar 29 '23 at 23:25