Как проверить, все ли перечисленные ниже элементы находятся в списке?


115

Я обнаружил, что есть связанный вопрос о том, как определить, существует ли хотя бы один элемент в списке:
как проверить, есть ли один из следующих элементов в списке?

Но каков наилучший и питонический способ узнать, все ли элементы существуют в списке?

Просматривая документы, я нашел это решение:

>>> l = ['a', 'b', 'c']
>>> set(['a', 'b']) <= set(l)
True
>>> set(['a', 'x']) <= set(l)
False

Другое решение было бы таким:

>>> l = ['a', 'b', 'c']
>>> all(x in l for x in ['a', 'b'])
True
>>> all(x in l for x in ['a', 'x'])
False

Но здесь вам нужно больше печатать.

Есть ли другие решения?


5
Что не так set(smaller) <= set(larger)?
eumiro

1
Я думаю, что ваши вторые решения со «всем» мне кажутся прекрасными и питоническими.
Jiho Noh

Ответы:


158

Такие операторы, как <=в Python, обычно не переопределяются для обозначения чего-то существенно отличного от «меньше или равно». Это необычно для стандартной библиотеки - для меня это пахнет устаревшим API.

Используйте эквивалентный метод с более понятным названием set.issubset. Обратите внимание, что вам не нужно преобразовывать аргумент в набор; при необходимости он сделает это за вас.

set(['a', 'b']).issubset(['a', 'b', 'c'])

2
не знал, что вы можете передать список напрямую в качестве аргумента в issubset ... хорошо!
tsimbalar

1
Хотя я согласен с чувством, я довольно хорошо с идеей <=и issubsetозначает то же самое. Почему тебе это не нравится?
Кирк Штраузер,

2
@Just: в первую очередь потому, что не очевидно, что <=означает набор, не просматривая его в документации или не имея предварительных знаний о том, что это означает в теории множеств, тогда как все знают, что issubsetозначает автоматически.
Гленн Мейнард,

2
Вы знаете математический оператор для (неправильного) подмножества? в основном он выглядит как закругленный <=;)
dom0

люблю это решение. есть ли способ получить местоположение индекса или значение списка вместо bool (True: False)?
Влад Гулин

62

Я бы, наверное, использовал setследующим образом:

set(l).issuperset(set(['a','b'])) 

или наоборот:

set(['a','b']).issubset(set(l)) 

Я считаю, что это немного более читабельно, но может быть чрезмерным. Наборы особенно полезны для вычисления объединения / пересечения / различий между коллекциями, но это может быть не лучший вариант в этой ситуации ...


Собственно MySet.issubset(MyOtherSet)и MySet <= MyOtherSetтакие же.
Wok

1
@wok: о, я этого не знал, но я думаю, что синтаксис <= немного сбивает с толку, поскольку аналогичный синтаксис может использоваться со списками, но с совершенно другим значением.
tsimbalar

3
На самом деле это не так запутанно, если вы помните, что включение определяет частичный порядок для любого набора множеств. На самом деле немного сбивает с толку то, что <=имеет значение, которое он имеет для последовательностей: можно было бы ожидать, что это означает «подпоследовательность», а не лексикографическое упорядочение.
aaronasterling

1
@aaronasterling: ммм, я лично не слишком задумываюсь о "частичном порядке", когда набираю код :-), но я согласен с тем, что использование <=с последовательностями тоже кажется странным, как-то ...
tsimbalar

3
Я побежал в маленькую Gotcha здесь я хотел бы упомянуть: Если вы используете этот метод, вы являетесь преобразование списков в наборы, что не означают дубликатов. set(['a','a']).issubset(['a'])возвращается True.
Orangestar

11

Мне нравятся эти два, потому что они кажутся наиболее логичными, последний из которых короче и, вероятно, самый быстрый (показан здесь с использованием setбуквального синтаксиса, который был перенесен на Python 2.7):

all(x in {'a', 'b', 'c'} for x in ['a', 'b'])
#   or
{'a', 'b'}.issubset({'a', 'b', 'c'})

Решение "все" является самым быстрым, если вы измеряете его с помощью timeit (). Это должен быть принятый ответ.
Аттерссон

3

Что делать, если в ваших списках есть такие дубликаты:

v1 = ['s', 'h', 'e', 'e', 'p']
v2 = ['s', 's', 'h']

Наборы не содержат дубликатов. Итак, следующая строка возвращает True.

set(v2).issubset(v1)

Для подсчета дубликатов вы можете использовать код:

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) 

Итак, следующая строка возвращает False.

is_subseq(v2, v1)

1

Это было то, что я искал в Интернете, но, к сожалению, нашел не в Интернете, а во время экспериментов с интерпретатором Python.

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

и если у вас есть длинный список переменных, хранящихся в 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
>>>
>>>

0

Пример того, как это сделать с помощью лямбда-выражения:

issublist = lambda x, y: 0 in [_ in x for _ in y]

1
Пожалуйста, добавьте комментарии, чтобы объяснить / уточнить свой ответ
Шарад

0

Не в случае OP, но - для всех, кто хочет утверждать пересечение в dicts и оказался здесь из-за плохого поиска в Google (например, я) - вам нужно работать с 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

Это потому что dict.items возвращает кортежи пар ключ / значение, и, как и любой объект в Python, они взаимозаменяемы.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.