Тип set в языке программирования Python

Раздел: Python -> Обучение Python

Основные возможности и способы работы с set

Как создать пустое множество?

Для создания пустого множества применяется конструктор set(). Использование фигурных скобок {} создает словарь, а не множество.

empty_set = set()
print(type(empty_set))  # 

Python set (тип set в python)

Множество можно создать из любого итерируемого объекта, например из списка или строки.

set_from_list = set([1, 2, 3])
set_from_string = set('hello')  # {'h', 'e', 'l', 'o'}

практические задания по python (практические задания по python)

TypeError возникает при попытке указать в качестве элемента изменяемый тип, например список или словарь.

s = {[1, 2]}  # TypeError: unhashable type: 'list'

уроки python с заданиями (уроки python с заданиями)

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

Метод add() добавляет один элемент, если его еще нет.

s = {1, 2, 3}
s.add(4)
s.add(2)  # ничего не произойдет, так как 2 уже есть
print(s)  # {1, 2, 3, 4}

Метод update() добавляет сразу несколько элементов из итерируемого объекта.

s = {1, 2}
s.update([3, 4, 5])
print(s)  # {1, 2, 3, 4, 5}

Попытка добавить изменяемый объект (например список) вызовет TypeError.

s = set()
s.add([1, 2])  # TypeError

Как удалить элемент из множества?

Метод remove() удаляет элемент, вызывая KeyError, если его нет. Для безопасного удаления используется discard().

s = {1, 2, 3}
s.remove(2)
s.discard(10)  # ошибки нет, элемент просто не удален
print(s)  # {1, 3}

pop() удаляет и возвращает произвольный элемент. Если множество пусто, возникает KeyError.

s = {10, 20, 30}
elem = s.pop()
print(elem, s)  # например 10 {20, 30}

Итерация по множеству с одновременным удалением элементов (кроме clear) может привести к RuntimeError: Set changed size during iteration.

s = {1, 2, 3}
for x in s:
    s.remove(x)  # RuntimeError

Как проверить наличие элемента в множестве?

Оператор in выполняет проверку за O(1) в среднем.

s = {1, 2, 3}
print(2 in s)  # True
print(4 in s)  # False

Также можно проверить отсутствие с помощью not in.

if 5 not in s:
    print('5 отсутствует')

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

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

Метод union() или оператор | возвращает новое множество, содержащее все элементы из обеих.

a = {1, 2, 3}
b = {3, 4, 5}
c = a.union(b)  # {1, 2, 3, 4, 5}
d = a | b  # то же самое

Метод update() изменяет исходное множество, добавляя элементы из другого.

a.update(b)  # a теперь {1, 2, 3, 4, 5}

Аргументы union и update могут быть любыми итерируемыми объектами, но добавление нехэшируемых элементов вызовет ошибку.

Как найти пересечение множеств?

Используется метод intersection() или оператор &.

a = {1, 2, 3}
b = {2, 3, 4}
c = a.intersection(b)  # {2, 3}
d = a & b  # {2, 3}

Метод intersection_update() изменяет исходное множество, оставляя только общие элементы.

a.intersection_update(b)  # a теперь {2, 3}

Пересечение с пустым множеством всегда пусто.

Как найти разность и симметрическую разность?

Разность (элементы из первого, но не из второго) difference() или -. Симметрическая разность (элементы, входящие в одно из множеств, но не в оба) symmetric_difference() или ^.

a = {1, 2, 3}
b = {2, 3, 4}
print(a - b)  # {1}
print(a ^ b)  # {1, 4}

Для изменения на месте существуют difference_update() и symmetric_difference_update().

a ^= b  # a становится {1, 4}

Симметрическая разность ассоциативна, но не коммутативна? На самом деле она коммутативна: a ^ b == b ^ a.

Как проверить, является ли одно множество подмножеством другого?

Методы issubset() (<=) и issuperset() (>=) проверяют включение.

a = {1, 2}
b = {1, 2, 3}
print(a.issubset(b))  # True
print(b.issuperset(a))  # True
print(a < b)  # строгое подмножество (a <= b и a != b)

isdisjoint() проверяет, не имеют ли множества общих элементов.

c = {4, 5}
print(a.isdisjoint(c))  # True (общих элементов нет)

При сравнении пустое множество является подмножеством любого множества.

Зачем нужен frozenset?

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

fs = frozenset([1, 2, 3])
d = {fs: 'value'}
print(d[fs])  # 'value'

frozenset поддерживает все немодифицирующие операции (union, intersection, …), возвращая frozenset.

fs2 = frozenset([2, 3, 4])
fs3 = fs.union(fs2)  # frozenset({1, 2, 3, 4})

Нельзя изменить frozenset после создания; отсутствуют методы add, remove и т.д.

Как убрать дубликаты из списка с помощью set?

Преобразование списка в множество удаляет дубликаты, затем обратно в список (порядок не сохраняется).

original = [1, 2, 2, 3, 1]
unique = list(set(original))
print(unique)  # [1, 2, 3] (порядок может быть другим)

Для сохранения порядка (Python 3.7+ dict сохраняет порядок) можно использовать dict.fromkeys().

unique_ordered = list(dict.fromkeys(original))
print(unique_ordered)  # [1, 2, 3] (порядок сохранен)

Если элементы списка нехэшируемы (например вложенные списки), set применить нельзя. Тогда нужна ручная проверка.

Специфические особенности работы с set

Множества в Python неупорядочены. Порядок итерации может меняться между запусками программы (до Python 3.7 была случайность, сейчас фиксирован, но не гарантирован).

Для работы с упорядоченными уникальными элементами используется OrderedSet (из модуля collections нет стандартного) или комбинация dict.

Изменять множество во время итерации по нему нельзя - создайте копию: for x in s.copy(): ...

Дополнительные примеры с set

Пример 1. Преобразование списка с дубликатами и сохранение порядка

Использование dict.fromkeys() для удаления дубликатов с сохранением первоначального порядка.

Пример
data = [3, 1, 2, 1, 3, 4]
unique = list(dict.fromkeys(data))
print(unique)
[3, 1, 2, 4]

Пример 2. Frozenset как ключ словаря

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

Пример
fs1 = frozenset([1, 2])
fs2 = frozenset([3, 4])
cache = {fs1: 'первая группа', fs2: 'вторая группа'}
print(cache[frozenset([1, 2])])
первая группа

Пример 3. Операции над множествами с выводом результатов

Демонстрируются все основные операции.

Пример
a = set('abracadabra')
b = set('alacazam')
print('a:', a)
print('b:', b)
print('a | b:', a | b)
print('a & b:', a & b)
print('a - b:', a - b)
print('a ^ b:', a ^ b)
a: {'b', 'a', 'c', 'r', 'd'}
b: {'l', 'a', 'c', 'z', 'm'}
a | b: {'b', 'a', 'c', 'r', 'd', 'l', 'z', 'm'}
a & b: {'a', 'c'}
a - b: {'b', 'r', 'd'}
a ^ b: {'b', 'r', 'd', 'l', 'z', 'm'}

Пример 4. Проверка подмножества и непересечения

Пример
x = {1, 2, 3}
y = {1, 2}
z = {4}
print(y.issubset(x))  # True
print(x.issuperset(y))  # True
print(x.isdisjoint(z))  # True
True
True
True

Пример 5. Set comprehension (генератор множеств)

Создание множества квадратов чисел от 0 до 9.

Пример
squares = {x**2 for x in range(10)}
print(squares)
{0, 1, 4, 9, 16, 25, 36, 49, 64, 81}

Пример 6. Быстрая проверка на вхождение (производительность)

Сравнение времени проверки для списка и множества.

Пример
import time
lst = list(range(100000))
st = set(range(100000))
start = time.perf_counter()
for _ in range(1000):
    99999 in lst
print('list:', time.perf_counter() - start)
start = time.perf_counter()
for _ in range(1000):
    99999 in st
print('set:', time.perf_counter() - start)
list: ~0.025 сек
set: ~0.0002 сек

Пример 7. Ошибка при итерации с удалением и способ обхода

Пример
s = {1, 2, 3, 4}
# неверно:
# for x in s:
#     if x % 2 == 0:
#         s.remove(x)
# верно:
for x in s.copy():
    if x % 2 == 0:
        s.remove(x)
print(s)
{1, 3}

Пример 8. Вложенные frozenset

Множество из frozenset возможно, так как frozenset хэшируем.

Пример
fs1 = frozenset([1, 2])
fs2 = frozenset([3, 4])
set_of_frozensets = {fs1, fs2}
print(set_of_frozensets)
{frozenset({1, 2}), frozenset({3, 4})}

Пример 9. Преобразование строки в множество символов и обратно

Пример
text = 'программирование'
unique_chars = set(text)
print(unique_chars)
sorted_chars = ''.join(sorted(unique_chars))
print(sorted_chars)
{'м', 'р', 'о', 'г', 'и', 'а', 'в', 'п', 'н', 'е'}
авгимнопре

Пример 10. Использование set для поиска общих элементов в нескольких последовательностях

Пример
list1 = [1, 2, 3, 4]
list2 = [3, 4, 5, 6]
list3 = [4, 5, 6, 7]
common = set(list1) & set(list2) & set(list3)
print(common)
{4}

Тип set в Python - comments

En
Python set (python)