How to check if all of the following items are in a list?
Question:
I found, that there is related question, about how to find if at least one item exists in a list:
How to check if one of the following items is in a list?
But what is the best and pythonic way to find whether all items exists in a list?
Searching through the docs I found this solution:
>>> l = ['a', 'b', 'c']
>>> set(['a', 'b']) <= set(l)
True
>>> set(['a', 'x']) <= set(l)
False
Other solution would be this:
>>> l = ['a', 'b', 'c']
>>> all(x in l for x in ['a', 'b'])
True
>>> all(x in l for x in ['a', 'x'])
False
But here you must do more typing.
Is there any other solutions?
Answers:
I would probably use set
in the following manner :
set(l).issuperset(set(['a','b']))
or the other way round :
set(['a','b']).issubset(set(l))
I find it a bit more readable, but it may be over-kill. Sets are particularly useful to compute union/intersection/differences between collections, but it may not be the best option in this situation …
Operators like <=
in Python are generally not overriden to mean something significantly different than “less than or equal to”. It’s unusual for the standard library does this–it smells like legacy API to me.
Use the equivalent and more clearly-named method, set.issubset
. Note that you don’t need to convert the argument to a set; it’ll do that for you if needed.
set(['a', 'b']).issubset(['a', 'b', 'c'])
I like these two because they seem the most logical, the latter being shorter and probably fastest (shown here using set
literal syntax which has been backported to Python 2.7):
all(x in {'a', 'b', 'c'} for x in ['a', 'b'])
# or
{'a', 'b'}.issubset({'a', 'b', 'c'})
What if your lists contain duplicates like this:
v1 = ['s', 'h', 'e', 'e', 'p']
v2 = ['s', 's', 'h']
Sets do not contain duplicates. So, the following line returns True.
set(v2).issubset(v1)
To count for duplicates, you can use the code:
v1 = sorted(v1)
v2 = sorted(v2)
def is_subseq(v2, v1):
"""Check whether v2 is a subsequence of v1."""
it = iter(v1)
return all(c in it for c in v2)
So, the following line returns False.
is_subseq(v2, v1)
Short syntax
I discovered a very readable syntax while experimenting on the Python interpreter.
>>> my_list = [1, 2, 3, 4, 5]
>>> (6 or 7) in my_list
False
>>> (2 or 6) in my_list
True
>>> (2 and 6) in my_list
False
>>> (2 and 5) in my_list
True
List of items to search for
If you have a long list of objects to search for, held in a sub_list
variable:
>>> my_list = [1, 2, 3, 4, 5]
>>> sub_list = ['x', 'y']
If any (at least one) item is contained in the superset (or
statement):
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
False
>>> sub_list[0] = 3
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
True
If all items are contained in superset (and
statement), then sub_list
is a full subset. Also featuring a bit of De Morgan’s Law:
>>> next((False for item in sub_list if item not in my_list), True)
False
>>> sub_list[1] = 2
>>> next((False for item in sub_list if item not in my_list), True)
True
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
True
An example of how to do this using a lambda expression would be:
issublist = lambda x, y: 0 in [_ in x for _ in y]
Not OP’s case, but – for anyone who wants to assert intersection in dicts and ended up here due to poor googling (e.g. me) – you need to work with dict.items
:
>>> a = {'key': 'value'}
>>> b = {'key': 'value', 'extra_key': 'extra_value'}
>>> all(item in a.items() for item in b.items())
True
>>> all(item in b.items() for item in a.items())
False
That’s because dict.items
returns tuples of key/value pairs, and much like any object in Python, they’re interchangeably comparable
Another solution would be:
l = ['a', 'b', 'c']
potential_subset1 = ['a', 'b']
potential_subset2 = ['a', 'x']
print(False not in [i in l for i in potential_subset1]) # True
print(False not in [i in l for i in potential_subset2]) # False
What makes my solution great is that you can write one-liners by putting the lists inline.
I found, that there is related question, about how to find if at least one item exists in a list:
How to check if one of the following items is in a list?
But what is the best and pythonic way to find whether all items exists in a list?
Searching through the docs I found this solution:
>>> l = ['a', 'b', 'c']
>>> set(['a', 'b']) <= set(l)
True
>>> set(['a', 'x']) <= set(l)
False
Other solution would be this:
>>> l = ['a', 'b', 'c']
>>> all(x in l for x in ['a', 'b'])
True
>>> all(x in l for x in ['a', 'x'])
False
But here you must do more typing.
Is there any other solutions?
I would probably use set
in the following manner :
set(l).issuperset(set(['a','b']))
or the other way round :
set(['a','b']).issubset(set(l))
I find it a bit more readable, but it may be over-kill. Sets are particularly useful to compute union/intersection/differences between collections, but it may not be the best option in this situation …
Operators like <=
in Python are generally not overriden to mean something significantly different than “less than or equal to”. It’s unusual for the standard library does this–it smells like legacy API to me.
Use the equivalent and more clearly-named method, set.issubset
. Note that you don’t need to convert the argument to a set; it’ll do that for you if needed.
set(['a', 'b']).issubset(['a', 'b', 'c'])
I like these two because they seem the most logical, the latter being shorter and probably fastest (shown here using set
literal syntax which has been backported to Python 2.7):
all(x in {'a', 'b', 'c'} for x in ['a', 'b'])
# or
{'a', 'b'}.issubset({'a', 'b', 'c'})
What if your lists contain duplicates like this:
v1 = ['s', 'h', 'e', 'e', 'p']
v2 = ['s', 's', 'h']
Sets do not contain duplicates. So, the following line returns True.
set(v2).issubset(v1)
To count for duplicates, you can use the code:
v1 = sorted(v1)
v2 = sorted(v2)
def is_subseq(v2, v1):
"""Check whether v2 is a subsequence of v1."""
it = iter(v1)
return all(c in it for c in v2)
So, the following line returns False.
is_subseq(v2, v1)
Short syntax
I discovered a very readable syntax while experimenting on the Python interpreter.
>>> my_list = [1, 2, 3, 4, 5]
>>> (6 or 7) in my_list
False
>>> (2 or 6) in my_list
True
>>> (2 and 6) in my_list
False
>>> (2 and 5) in my_list
True
List of items to search for
If you have a long list of objects to search for, held in a sub_list
variable:
>>> my_list = [1, 2, 3, 4, 5]
>>> sub_list = ['x', 'y']
If any (at least one) item is contained in the superset (or
statement):
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
False
>>> sub_list[0] = 3
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
True
If all items are contained in superset (and
statement), then sub_list
is a full subset. Also featuring a bit of De Morgan’s Law:
>>> next((False for item in sub_list if item not in my_list), True)
False
>>> sub_list[1] = 2
>>> next((False for item in sub_list if item not in my_list), True)
True
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
True
An example of how to do this using a lambda expression would be:
issublist = lambda x, y: 0 in [_ in x for _ in y]
Not OP’s case, but – for anyone who wants to assert intersection in dicts and ended up here due to poor googling (e.g. me) – you need to work with dict.items
:
>>> a = {'key': 'value'}
>>> b = {'key': 'value', 'extra_key': 'extra_value'}
>>> all(item in a.items() for item in b.items())
True
>>> all(item in b.items() for item in a.items())
False
That’s because dict.items
returns tuples of key/value pairs, and much like any object in Python, they’re interchangeably comparable
Another solution would be:
l = ['a', 'b', 'c']
potential_subset1 = ['a', 'b']
potential_subset2 = ['a', 'x']
print(False not in [i in l for i in potential_subset1]) # True
print(False not in [i in l for i in potential_subset2]) # False
What makes my solution great is that you can write one-liners by putting the lists inline.