158

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?

Community
  • 1
  • 1
sirex
  • 4,147
  • 2
  • 29
  • 20
  • 6
    What's wrong with `set(smaller) <= set(larger)` ? – eumiro Oct 14 '10 at 08:58
  • 1
    I think your second solutions with 'all' looks just fine and pythonic to me. – Jiho Noh Jun 24 '18 at 14:25
  • Same question as [Python: See if one set contains another entirely? - Stack Overflow](https://stackoverflow.com/questions/2765892/python-see-if-one-set-contains-another-entirely) except for the list/set distinction. – user202729 Dec 05 '21 at 18:00

8 Answers8

242

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'])
Glenn Maynard
  • 53,510
  • 10
  • 114
  • 128
  • 2
    didn't know you could pass the list directly as an argument to issubset ... nice ! – tsimbalar Oct 14 '10 at 09:10
  • 2
    While I agree with the sentiment, I'm pretty OK with the idea of `<=` and `issubset` meaning the same thing. Why do you dislike it? – Kirk Strauser Oct 14 '10 at 13:25
  • 8
    @Just: Primarily, because it's not obvious what `<=` means for a set without either looking it up in the docs or having a prior knowledge of what it means in set theory, whereas everyone knows what `issubset` means automatically. – Glenn Maynard Oct 14 '10 at 21:04
  • 4
    You know the mathematical operator for (non-proper) subset? it basically looks pretty much like a rounded <= ;) – dom0 Aug 14 '13 at 22:48
  • love this solution. is there a way to get an index location or a list value instead of a bool (True:False)? – Vlad Gulin Nov 16 '18 at 23:05
69

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

tsimbalar
  • 5,600
  • 6
  • 38
  • 57
  • Actually, `MySet.issubset(MyOtherSet)` and `MySet <= MyOtherSet` are the same. – Wok Oct 14 '10 at 09:03
  • 1
    @wok : oh I didn't know that, but I think the <= syntax is a bit confusing as a similar syntax can be used with lists, but with a very different meaning. – tsimbalar Oct 14 '10 at 09:07
  • 3
    it's not really that confusing if you recall the inclusion defines a partial order on any set of sets. It's actually slightly confusing that `<=` has the meaning it does for sequences: one might expect it to mean 'is a subsequence` of rather than lexicographical ordering. – aaronasterling Oct 14 '10 at 09:12
  • 1
    @aaronasterling : mmm, I personnally don't think too much about "partial order" when I type code :-), but I agree on the fact that using `<=` with sequences also feels strange, somehow ... – tsimbalar Oct 14 '10 at 09:16
  • Comparison operators only defining a partial order--whether or not you know what it's called :)--are fairly unusual. I think most people intuitively expect that `!(a <= b)` implies `b <= a`, which a partial order does not--both `set([1]) <= set([2])` and `set([2]) <= set([1])` are false. – Glenn Maynard Oct 14 '10 at 09:35
  • 5
    I ran into a little gotcha here I'd like to mention: If you use this method, you *are* converting your lists to sets, which means no duplicates. `set(['a','a']).issubset(['a'])` returns `True`. – Orangestar Dec 22 '15 at 08:47
19

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'})
martineau
  • 112,593
  • 23
  • 157
  • 280
  • The "all" solution is the quickest when you measure it with timeit(). This should be the accepted answer. – Attersson Feb 06 '19 at 12:05
12

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)
Max
  • 1,487
  • 13
  • 21
2

This was what I was searching for online. However unfortunately did not find online, but while experimenting on python interpreter.

>>> case  = "caseCamel"
>>> label = "Case Camel"
>>> list  = ["apple", "banana"]
>>>
>>> (case or label) in list
False
>>> list = ["apple", "caseCamel"]
>>> (case or label) in list
True
>>> (case and label) in list
False
>>> list = ["case", "caseCamel", "Case Camel"]
>>> (case and label) in list
True
>>>

and if you have a looong list of variables held in a sublist variable

>>>
>>> list  = ["case", "caseCamel", "Case Camel"]
>>> label = "Case Camel"
>>> case  = "caseCamel"
>>>
>>> sublist = ["unique banana", "very unique banana"]
>>>
>>> # example for if any (at least one) item contained in superset (or statement)
...
>>> next((True for item in sublist if next((True for x in list if x == item), False)), False)
False
>>>
>>> sublist[0] = label
>>>
>>> next((True for item in sublist if next((True for x in list if x == item), False)), False)
True
>>>
>>> # example for whether a subset (all items) contained in superset (and statement)
...
>>> # a bit of demorgan's law
...
>>> next((False for item in sublist if item not in list), True)
False
>>>
>>> sublist[1] = case
>>>
>>> next((False for item in sublist if item not in list), True)
True
>>>
>>> next((True for item in sublist if next((True for x in list if x == item), False)), False)
True
>>>
>>>
ctrl-alt-delor
  • 7,028
  • 5
  • 35
  • 49
Emirhan Özlen
  • 468
  • 2
  • 14
1

An example of how to do this using a lambda expression would be:

issublist = lambda x, y: 0 in [_ in x for _ in y]
heckj
  • 6,638
  • 3
  • 40
  • 47
Jundullah
  • 115
  • 2
  • 11
1

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

Julio Cezar Silva
  • 1,670
  • 1
  • 14
  • 27
1

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.

Johann Lau
  • 153
  • 1
  • 14