Множества set в Python: пересечение, объединение и разность

Python Автор: Среда и версия: CPython 3.14.7
содержание

Множество set в Python хранит уникальные хешируемые элементы и подходит для сравнения наборов. Если есть участники двух занятий, a & b найдёт тех, кто был на обоих, a | b — на любом из двух, а a - b — только на первом. Позиции элементов и порядок добавления множество не сохраняет.

Для предсказуемого вывода используется sorted: это сортировка результата для показа, а не свойство самого множества.

Как создать множество: set(), фигурные скобки и пустой набор

Непустое множество создаётся перечислением элементов в фигурных скобках. set(iterable) собирает множество из строки, списка или другого итерируемого объекта:

attendees = {101, 102, 103}
from_list = set([101, 102, 101, 103])
empty_set = set()
empty_dict = {}

print(attendees == from_list)
print(len(from_list))
print(type(empty_set).__name__)
print(type(empty_dict).__name__)
True
3
set
dict

Пустое множество — set(). Запись {} создаёт словарь. Повтор 101 из списка не увеличивает размер множества. Создание множеств и проверка вхождения показаны в учебнике Python.

Строка тоже перебирается по элементам. set("abac") содержит отдельные символы a, b, c; для множества из одной строки нужна запись {"abac"}. set(user_id) разобьёт строковый идентификатор на символы.

Пересечение, объединение и разность множеств

На первое занятие пришли 101, 102, 103, на второе — 102, 103, 104. Сравним списки посещений:

first = {101, 102, 103}
second = {102, 103, 104}

print("Оба занятия:", sorted(first & second))
print("Хотя бы одно:", sorted(first | second))
print("Только первое:", sorted(first - second))
print("Только второе:", sorted(second - first))
print("Ровно одно:", sorted(first ^ second))
Оба занятия: [102, 103]
Хотя бы одно: [101, 102, 103, 104]
Только первое: [101]
Только второе: [104]
Ровно одно: [101, 104]

Разность зависит от порядка: first - second и second - first отвечают на разные вопросы. Симметрическая разность ^ собирает обе такие группы и исключает общих участников.

Python / 01

Два набора посещений — три ответа

Пересечение, объединение и разность множествПервый шаг: a содержит 101, 102, 103, b содержит 102, 103, 104. Второй шаг: операции пересечения, объединения и разности. Третий шаг: a пересечение b равно 102, 103; объединение равно 101, 102, 103, 104; a минус b равно 101.01 / исходные наборыa = {101, 102, 103}b = {102, 103, 104}02 / операция03 / результатa & bпришли на оба занятия{102, 103}a | bпришли хотя бы на одно{101, 102, 103, 104}a - bпришли только на первое{101}
Общие участники — 102 и 103. Разность a - b оставляет только 101; участник 104 в исходное a не входит.

У операторов есть методы с теми же результатами:

ЗадачаОператорМетод
Пересечениеa & ba.intersection(b)
Объединениеa | ba.union(b)
Разностьa - ba.difference(b)
Симметрическая разностьa ^ ba.symmetric_difference(b)

Операторы в таблице ожидают множества с обеих сторон, а методы принимают и другие итерируемые объекты. Например, first.intersection([102, 104]) работает без отдельного set(...). Все эти варианты создают результат, сохраняя исходное first. Различие методов и операторов описано в справочнике set.

Проверка вхождения, подмножества и отсутствия общих элементов

in проверяет отдельного участника. Оператор <= проверяет, целиком ли один набор входит в другой:

registered = {101, 102, 103, 104}
attended = {101, 103}
waiting = {105, 106}

print(102 in registered)
print(102 not in attended)
print(attended <= registered)
print(attended < registered)
print(attended.isdisjoint(waiting))
True
True
True
True
True

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

isdisjoint отвечает, нет ли общих элементов. Здесь никто из пришедших не находится в листе ожидания. Если требуется лишь ответ «да/нет», этот вызов выражает задачу без создания отдельного пересечения.

add, update, discard и remove: как менять set

add добавляет один элемент, update — элементы из переданного набора. Повторное добавление уже присутствующего идентификатора ничего не меняет:

attendees = {101}
attendees.add(102)
attendees.add(102)
attendees.update([103, 104])
attendees.discard(999)
attendees.remove(104)

print(sorted(attendees))

try:
    attendees.remove(999)
except KeyError:
    print("Участник 999 отсутствует")
[101, 102, 103]
Участник 999 отсутствует

discard подходит, когда отсутствие элемента допустимо. remove поднимает KeyError, если элемента нет: так потерянная запись не останется незамеченной. Оба метода меняют множество и возвращают None, поэтому запись attendees = attendees.add(105) затрёт ссылку на набор.

Для изменения сразу по правилу есть intersection_update, difference_update и операторы &=, -=. Например, attendees -= {101} удалит 101 из того же объекта. Если исходный набор ещё нужен, возьми выражение remaining = attendees - {101}.

Метод pop() удаляет произвольный элемент. Для очереди «первый пришёл — первый вышел» он не подходит: у множества нет первого элемента по времени добавления.

Какие элементы допустимы и зачем нужен frozenset

Элемент множества должен быть хешируемым: его хеш стабилен, а равные объекты дают одинаковый хеш. Числа и строки подходят. Список и словарь не подходят; кортеж подходит, только если хешируемы все его элементы. Это правило определено в глоссарии Python.

groups = set()
groups.add((101, 102))

try:
    groups.add([103, 104])
except TypeError:
    print("Список нельзя сделать элементом set")

group = frozenset({103, 104})
groups.add(group)
print(group in groups)
print(group == frozenset({104, 103}))
Список нельзя сделать элементом set
True
True

frozenset — неизменяемое множество. Его удобно использовать как ключ словаря или элемент другого множества. В примере группа участников не зависит от порядка перечисления: {103, 104} и {104, 103} описывают одну группу. Кортежи (103, 104) и (104, 103), напротив, были бы разными.

В Python 1, 1.0 и True равны и имеют согласованные хеши, поэтому len({1, 1.0, True}) даёт 1. Требования к равенству и хешу описаны в модели данных. При сборе идентификаторов из чужого JSON проверяй типы до преобразования в множество, иначе ошибочный True может совпасть с идентификатором 1.

Самопроверка на двух наборах участников

Этот блок проверяет все четыре операции, пустое пересечение и сохранность входных данных. Он запускается без файлов и дополнительных пакетов:

first = {101, 102, 103}
second = {102, 103, 104}

assert first & second == {102, 103}
assert first | second == {101, 102, 103, 104}
assert first - second == {101}
assert second - first == {104}
assert first ^ second == {101, 104}
assert first & set() == set()
assert first - first == set()
assert first == {101, 102, 103}
assert second == {102, 103, 104}

first.discard(999)
assert first == {101, 102, 103}
assert len({1, 1.0, True}) == 1
print("Операции и граничные случаи проверены")
Операции и граничные случаи проверены

Добавь в second идентификатор 105. До запуска предскажи, какие результаты изменятся: пересечение и first - second должны остаться прежними, объединение и симметрическая разность получат новый элемент.

Если задача состоит в удалении повторов с сохранением порядка, одного set недостаточно: используй разбор стабильной дедупликации. Когда нужна позиция элемента или повторяющиеся записи, подходящей структурой останется список.

Источники