Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find out if the elements in one list are in another? [duplicate]

I have two lists:

A = [[2, 5, 13, 14], [4, 5, 10, 12], [2, 9, 10, 11], [2, 5, 12, 13], [4, 5, 6, 12]]
B = [12, 5]

I'm trying to find out which lists in A contain the elements in B (order doesn't matter) and get rid of the rest of the lists.

In this case the answers is:

[[4, 5, 10, 12], [2, 5, 12, 13], [4, 5, 6, 12]]

If we change B and make it B = [13], the answer would be:

[[2, 5, 13, 14], [2, 5, 12, 13]]
like image 388
Ryan Smith Avatar asked Apr 19 '15 21:04

Ryan Smith


2 Answers

You can use set.issubset with a list comprehension, using A[:] will change the original/list object A:

A = [[2, 5, 13, 14], [4, 5, 10, 12], [2, 9, 10, 11], [2, 5, 12, 13], [4, 5, 6, 12]]
B = [12, 5]
st = set(B)

A [:] = [sub for sub in A if st.issubset(sub)]

print(A)
[[4, 5, 10, 12], [2, 5, 12, 13], [4, 5, 6, 12]]

Same for B = [13]

A = [[2, 5, 13, 14], [4, 5, 10, 12], [2, 9, 10, 11], [2, 5, 12, 13], [4, 5, 6, 12]]
B = [13]
st = set(B)

A [:] = [sub for sub in A if st.issubset(sub)]

print(A)
[[2, 5, 13, 14], [2, 5, 12, 13]]

set objects

s.issubset(t) s <= t test whether every element in s is in t

For very large A or if you have memory restrictions you can use a generator expression:

A [:] = (sub for sub in A if st.issubset(sub))

If order never matters and it is possible to sets I would suggest you using them from the very beginning. Doing lookups on sets will be a lot more efficient.

Some timings on a slightly larger A:

In [23]: A = [[2, 5, 13, 14], [4, 5, 10, 12], [2, 9, 10, 11], [2, 5, 12, 13], [4, 5, 6, 12],[2, 5, 13, 14], [4, 5, 10, 12], [2, 9, 10, 11], [2, 5, 12, 13], [4, 5, 6, 12],[2, 5, 13, 14], [4, 5, 10, 12], [2, 9, 10, 11], [2, 5, 12, 13], [4, 5, 6, 12]]

In [24]: B = [12, 5]                                 
In [25]: timeit  filter(lambda x: all(y in x for y in B), A)
100000 loops, best of 3: 9.45 µs per loop

In [26]: %%timeit                                    
st = set(B)
[sub for sub in A if st.issubset(sub)]
   ....: 
100000 loops, best of 3: 3.88 µs per loop
 map(lambda x: not B_set-set(x), A)
In [27]: %%timeit
....: B_set = set(B)
....: map(lambda x: not B_set-set(x), A)
....: 
100000 loops, best of 3: 6.95 µs per loop

If you already had the elements stored as sets in A:

In [33]: %%timeit                             
st = set(B)
[sub for sub in A if sub >= st]
....: 
1000000 loops, best of 3: 1.12 µs per loop
like image 157
Padraic Cunningham Avatar answered Nov 15 '22 12:11

Padraic Cunningham


You can use filter in combination with all here:

print filter(lambda x: all(y in x for y in B), A)

A bit more efficient answer:

B_set = set(B)
print map(lambda x: not B_set-set(x), A)
like image 30
Saksham Varma Avatar answered Nov 15 '22 13:11

Saksham Varma