Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 6 из 20 Начальный 15 мин 100 XP

Объединение множеств в Python: оператор | и union

Гости субботы плюс гости воскресенья — но каждый посчитан один раз. Оператор | и метод union собирают два множества в одно без дубликатов.

Редакция Питоники

Одиночное множество — начало. Настоящая сила множеств раскрывается в операциях над парами: собрать всех гостей двух дней, все теги двух статей, все товары двух складов. Первая операция — объединение: всё, что есть хотя бы в одном из множеств, без повторов. У неё два лица: оператор | для лаконичного кода и метод union для работы с произвольными коллекциями. Разберём оба и главное правило подсчёта.

Задача: гости выходных

Клуб ведёт учёт посетителей по дням: в субботу приходили одни, в воскресенье — другие, часть гостей сходила оба дня. Вопрос: сколько разных людей побывало за выходные:

объединение двух дней
saturday = {'анна', 'борис', 'вера'}
sunday = {'вера', 'глеб', 'дарья'}
all_guests = saturday | sunday
print(sorted(all_guests))
print('за два дня:', len(all_guests))
Вывод
['анна', 'борис', 'вера', 'глеб', 'дарья']
за два дня: 5

Пять гостей вместо шести записей: вера есть в обоих множествах, но в объединение попала один раз. Оператор | взял два множества и вернул третье — со всеми элементами каждого.

Сначала списком: дубликаты в придачу

Сравним со списочным решением той же задачи. Списки складываются знаком плюс — и вносят в сумму все дубликаты:

сложение списков несёт дубли
saturday = ['анна', 'борис', 'вера']
sunday = ['вера', 'глеб', 'дарья']
combined = saturday + sunday
print('в списке:', len(combined))
print(sorted(set(combined)))
Вывод
в списке: 6
['анна', 'борис', 'вера', 'глеб', 'дарья']

Шесть имён в списке, пять настоящих гостей: вера задвоилась, и снимать дубль пришлось отдельным вызовом set. Множества делают это при объединении — лишней строки не нужно.

Оператор | и метод union

Объединение пишут и методом union — результат тот же самый, это одна и та же операция в двух записях:

| и union дают одно и то же
a = {1, 2, 3}
b = {3, 4}
print(sorted(a | b))
print(sorted(a.union(b)))
print(a | b == a.union(b))
Вывод
[1, 2, 3, 4]
[1, 2, 3, 4]
True

Тройка общая — в объединении она одна. Оператор лаконичнее и уместен, когда оба операнда уже множества; метод читается словом и уместен, когда второй набор пришёл списком. Проверим подсчёт на числах, где видно каждое значение:

общий элемент считается один раз
a = {1, 2, 3}
b = {3, 4}
u = a | b
print('у a:', len(a), '- у b:', len(b), '- в объединении:', len(u))
Вывод
у a: 3 - у b: 2 - в объединении: 4

Три плюс два равно пять, но в объединении четыре: общая тройка вошла один раз. Общее правило подсчёта: длина объединения равна сумме длин минус число общих элементов. Оно же — определение уникальности: пересечение не удваивается.

union принимает список, | — нет

Метод union растёт из общего принципа множеств: всё перебираемое годится. Поэтому второй набор может быть и списком — union сам соберёт его в множество и вольёт:

union со списком
a = {1, 2}
merged = a.union([3, 4])
print(sorted(merged))
try:
    a | [3, 4]
except TypeError as e:
    print('Ошибка:', e)
Вывод
[1, 2, 3, 4]
Ошибка: unsupported operand type(s) for |: 'set' and 'list'

Метод проглотил список и дал четыре элемента. Оператор на том же вызове упал: сообщение перечисляет типы обеих сторон — set и list — и отказывается их смешивать. Правило короткое: | для пары множеств, union для множества с чем угодно перебираемым.

Исходные не меняются: union возвращает новое

Объединение не трогает свои источники: | и union строят новое множество и оставляют оба набора нетронутыми. Проверим:

исходные множества целы
a = {1, 2}
b = {2, 3}
u = a | b
print(sorted(a), sorted(b))
print(sorted(u))
print(len(a), len(b))
Вывод
[1, 2] [2, 3]
[1, 2, 3]
2 2

Оба исходных множества остались при своих двух элементах, а объединение живёт в новой переменной. Это отличается от поведения update из урока про add и update: тот вливает элементы в существующее множество и ничего не возвращает. Выбор простой: нужно расширяющееся множество — update; нужно новое множество из двух — union.

А вот цикл с add для вливания пачки — наследие списочного мышления. Он работает, но вручную повторяет то, что операции множеств делают одним вызовом:

антипаттерн: пачка через цикл
merged = set()
for guest in saturday:
    merged.add(guest)
for guest in sunday:
    merged.add(guest)
# всё это один вызов: merged = saturday | sunday
Фрагмент приведён как контраст и не запускается: saturday и sunday здесь не объявлены. Тот же результат даёт один вызов merged = saturday | sunday — без циклов.

Объединение трёх множеств

Оператор можно выстроить в цепочку: a | b | c вычисляется слева направо — сначала объединение первых двух, потом к результату добавляется третье. Соберём стек технологий из трёх направлений:

цепочка из трёх множеств
mono = {'python', 'regex'}
web = {'python', 'flask'}
data = {'pandas', 'python'}
stack = mono | web | data
print(sorted(stack))
print(len(stack))
Вывод
['flask', 'pandas', 'python', 'regex']
4

Шесть записей в трёх множествах, четыре уникальных: питон повторялся во всех трёх и попал в стек один раз. Метод тоже цепляется: mono.union(web, data) — union, в отличие от оператора, принимает несколько аргументов сразу.

Шпаргалка объединения

Две записи одной операции и близнец update — всё объединение умещается в таблицу:

ВыражениеЧто делаетОсобенность
a | bНовое множество из всех элементовОбе стороны — множества
a.union(b)То же объединение, методомПринимает список и перебираемое
a.union(b, c)Объединение трёх и большеАргументы через запятую
a.update(b)Вливает b в a на местеВозвращает None, меняет a
a + bТакой операции нетДля списков плюс несёт дубликаты

Объединение собирает всех участников сцены. Обратный вопрос — кто присутствует в обоих множествах сразу — отвечает пересечение: оператор & и метод intersection из следующего урока. А быструю проверку принадлежности, которая лежит в основе всех этих операций, мы разобрали в уроке про in.

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

a = {1, 2}
b = {2, 3}
print(sorted(a | b))
print(len(a), len(b), len(a | b))
x = {'a'}
y = x.union(['b'])
print(sorted(x))
print(sorted(y))
print(len(x) == len(y))
mono = {1, 2}
web = {2, 3}
data = {3, 4}
all_x = mono | web | data
print(sorted(all_x))
print(len(all_x))
Проверь себя
0 / 6

1. Что вернёт {1, 2} | {2, 3}?

2. Чем a.union(b) отличается от a.update(b)?

3. Что произойдёт с общими элементами двух множеств при объединении?

4. Что вернёт a.union([3, 4]), если a — множество {1, 2}?

5. Что произойдёт при a | [3, 4]?

6. Как объединить три множества a, b и c?

Карточки терминов
Запомнено: 0 / 7
Практика

Даны гости двух дней: first_day = {'vk', 'tg'} и second_day = {'tg', 'ok'}. Соберите всех гостей через | в переменную weekend и напечатайте отсортированный список и количество гостей.

practice.py
Вопросы и ответы по уроку

Как объединить два множества в Python?

Оператором | или методом union: saturday | sunday вернёт новое множество со всеми элементами обоих, и общие элементы войдут один раз. Исходные множества не меняются. Для цепочки — a | b | c.

Урок 7: пересечение множеств

Чем оператор | отличается от union?

Только требованиями к аргументам. | работает с парой множеств и падает на списке; union принимает любой перебираемый — список, кортеж, строку — и даже несколько аргументов сразу: a.union(b, c). Результат обеих записей одинаков.

Почему объединение не создаёт дубликаты?

Потому что результат — множество: уникальность встроена в структуру. Общие элементы двух наборов кладутся в новую хеш-таблицу, где каждое значение живёт один раз. Поэтому длина объединения равна сумме длин минус число общих элементов.

Как объединить список с множеством?

Методом union: a.union([3, 4]) соберёт множество из a и списка. Оператор | так не умеет — он требует множество с обеих сторон и падает с TypeError на списке. Альтернатива — a | set([3, 4]).

Чем union отличается от update?

Результатом. union возвращает новое множество и оставляет источники нетронутыми; update вливает второй набор в первое множество на месте и возвращает None. Нужен расширяющийся список гостей — update; нужно новое множество из двух — union.

Урок 3: add и update

Понравился урок? Сошлитесь на него

«Общее правило подсчёта: длина объединения равна сумме длин минус число общих элементов.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.