Python: посмотреть, содержит ли один набор другой целиком?

Есть ли быстрый способ проверить, содержит ли один набор полностью другой?

Что-то типа:

>>>[1, 2, 3].containsAll([2, 1])
True

>>>[1, 2, 3].containsAll([3, 5, 9])
False

person Nick Heiner    schedule 04.05.2010    source источник


Ответы (7)


Это списки, но если вы действительно имеете в виду наборы, вы можете использовать issubset метод.

>>> s = set([1,2,3])
>>> t = set([1,2])
>>> t.issubset(s)
True
>>> s.issuperset(t)
True

Для списка вы не сможете добиться большего успеха, чем проверка каждого элемента.

person danben    schedule 04.05.2010
comment
У меня странное чувство дежавю, когда я вижу этот ответ - person Christophe Roussy; 27.07.2016
comment
вы должны знать о семантике issubset() не contains() - person wikier; 12.07.2019

Для полноты: это эквивалентно issubset (хотя, возможно, немного менее явно/читабельно):

>>> set([1,2,3]) >= set([2,1])
True
>>> set([1,2,3]) >= set([3,5,9])
False
person ChristopheD    schedule 04.05.2010
comment
Проблема в том, что a = set([]) и b = set(['a','b']), тогда a.issubset(b) равно True - person darkman; 12.08.2019

Вы можете использовать либо set.issubset(), либо set.issuperset() (или их аналоги на основе операторов: <= и >=). Обратите внимание, что методы будут принимать в качестве аргумента любой итерируемый объект, а не только набор:

>>> {1, 2}.issubset([1, 2, 3])
True
>>> {1, 2, 3}.issuperset([1, 2])
True

Однако, если вы используете операторы, оба аргумента должны быть установлены:

>>> {1, 2} <= {1, 2, 3}
True
>>> {1, 2, 3} >= {1, 2}
True
person Eugene Yarmash    schedule 13.02.2019

Один вариант остался нетронутым — вычитание:

>>> {1, 2} - {1, 2, 3}
set([])
>>> {1, 2, 3} - {1, 2}
set([3])

В основном вы проверяете, какие элементы в первом списке отсутствуют во втором списке.

Я нашел это очень удобным, так как вы могли показать, каких значений не хватает:

>>> def check_contains(a, b):
...     diff = a - b
...     if not diff:
...         # All elements from a are present in b
...         return True
...     print('Some elements are missing: {}'.format(diff))
...     return False
...
>>> check_contains({1, 2}, {1, 2, 3})
True
>>> check_contains({1, 2, 3}, {1, 2})
Some elements are missing: set([3])
False
person Artem Skoretskiy    schedule 13.04.2016

Если вы подозреваете, что набор является подмножеством другого, и пересекаете эти два множества вместе, результат равен самому себе, если это подмножество.

a = [2,1,3,3]
b = [5,4,3,2,1]
set(a).intersection(set(b)) == set(a)
>>True
person Jordan Stefanelli    schedule 06.06.2016
comment
Пусть A = set(a) и B = set(b) для вменяемости. Тогда это сравнение эффективно сводится к len(A.intersection(B)) == len(A). То есть сами наборы не должны сравниваться по элементам; нужно сравнивать только мощность этих наборов. Однако даже этой оптимизации, вероятно, недостаточно, чтобы сделать этот подход предпочтительным. Значительно более читаемые и эффективные подходы issubset() и <= почти наверняка нужны всем. - person Cecil Curry; 09.02.2018
comment
@CecilCurry Верно - я неправильно использовал слово «мощность», поскольку это измерение длины. Я обновил формулировку. Ваша оптимизация является ошибкой, основанной на моей ошибке. Не оптимизация. Буквальная формулировка пересечения () читается более явно, чем перегруженные последствия ›=, и заявление о том, что issubset () легче читать, является своего рода устранением очевидного, поскольку это самый популярный ответ. Не стесняйтесь предлагать творческое решение, помимо повторения ответов других. - person Jordan Stefanelli; 04.07.2019

Ниже функция возвращает 0, если основной список не полностью содержит подсписок, и 1, если содержит полностью.

def islistsubset(sublist,mainlist):
     for item in sublist:
             if item in mainlist:
                     contains = 1
             else:
                     contains = 0
                     break;
     return contains
person Bobin Motti Thomas    schedule 25.10.2017
comment
Это O (n ^ 2) при использовании операций над множествами, поскольку в некоторых из существующих ответов это происходит намного быстрее. Это также можно записать просто any(item in mainlist for item in sublist). - person Iguananaut; 25.10.2017
comment
Согласитесь, я мог бы также написать def islistsubset(sublist,mainlist): contains = 1 для элемента в подсписке: if item in mainlist: continue else: contains = 0 break; return содержит Таким образом, только 2 назначения на вызов - person Bobin Motti Thomas; 26.10.2017
comment
@BobinMottiThomas Вы можете просто напрямую вернуть True или False без создания какой-либо временной переменной. для элемента в list_a: если элемента нет в list_b: вернуть False вернуть True - person Jordan Stefanelli; 26.10.2017

person    schedule
comment
Подумайте о том, чтобы правильно отформатировать ответ и добавить некоторые пояснения. - person Sam; 26.01.2018