Что такое множество (Set) в Python и каковы его основные свойства?

Ответ

Множество (Set) в Python — это встроенная изменяемая коллекция уникальных и хешируемых объектов, не имеющая порядка (неиндексируемая). Реализована на основе хеш-таблицы, что обеспечивает очень быструю (в среднем O(1)) проверку вхождения элемента (in).

Ключевые свойства и операции:

  • Создание:

    my_set = {1, 2, 3}           # Использование фигурных скобок
    empty_set = set()            # Пустое множество. {} — создаст словарь!
    from_list = set([1, 2, 2, 3]) # {1, 2, 3} — дубликаты удаляются
  • Основные операции (модифицируют исходное множество):

    s = {1, 2, 3}
    s.add(4)          # {1, 2, 3, 4}
    s.remove(2)       # {1, 3, 4}. KeyError, если элемента нет
    s.discard(10)     # {1, 3, 4}. Удаляет, если есть (без ошибки)
    popped = s.pop()  # Удаляет и возвращает случайный элемент (т.к. порядка нет)
    s.clear()         # set()
  • Теоретико-множественные операции:

    a = {1, 2, 3, 4}
    b = {3, 4, 5, 6}
    
    union = a | b           # {1, 2, 3, 4, 5, 6} (объединение)
    intersection = a & b     # {3, 4} (пересечение)
    difference = a - b       # {1, 2} (разность: элементы в a, но не в b)
    sym_diff = a ^ b         # {1, 2, 5, 6} (симметрическая разность)
    
    # Есть также методы, не создающие новый объект:
    a.update(b)             # a |= b. Добавляет в 'a' все элементы из 'b'
    a.intersection_update(b)# a &= b. Оставляет в 'a' только общие элементы
  • Проверки:

    a = {1, 2}
    b = {1, 2, 3}
    print(a <= b)           # True. a является подмножеством b (issubset)
    print(b >= a)           # True. b является надмножеством a (issuperset)
    print(a.isdisjoint({5, 6})) # True. Множества не пересекаются

Типичные сценарии использования:

  1. Удаление дубликатов из списка: unique_list = list(set(duplicate_list)) (порядок может быть потерян).
  2. Проверка членства: Гораздо быстрее, чем element in list, особенно для больших коллекций.
  3. Нахождение общих/уникальных элементов: Например, общие теги у двух статей (tags1 & tags2).
  4. Моделирование математических множеств.

Важное ограничение: Элементами множества могут быть только хешируемые (неизменяемые) типы: числа, строки, кортежи (из хешируемых элементов). Списки, словари и другие множества — нельзя.

Ответ 18+ 🔞

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

Множество (Set) — это как такой особенный мешок, куда ты можешь кидать что угодно, но повторяться там ничего не будет. Вообще. Представь, пытаешься засунуть в холодильник вторую одинаковую банку пива — она просто не лезет, ёпта. И порядок в этом мешке — понятие условное, он там всё как бог на душу положит.

Как этот мешок завести?

my_set = {1, 2, 3}           # Просто взял и в фигурных скобках накидал
empty_set = set()            # А вот пустой так делай! {} — это словарь получится, обманешь сам себя.
from_list = set([1, 2, 2, 3]) # {1, 2, 3} — все дубликаты, блядь, нахуй автоматически выкинулись. Удобно же!

Основные фокусы с этим мешком (он меняется прямо на месте):

s = {1, 2, 3}
s.add(4)          # {1, 2, 3, 4} — кинул четвёрку, и всё.
s.remove(2)       # {1, 3, 4} — выкинул двойку. Но смотри, если её нет — будет тебе `KeyError`, как ножом по яйцам.
s.discard(10)     # {1, 3, 4} — а вот это по-пацански: если элемент есть — выкинул, нет — и хуй с ним, ошибки не будет.
popped = s.pop()  # Выдернул и отдал тебе какой-то *случайный* элемент. Порядка-то нет, вот он и хватает что первое попалось.
s.clear()         # set() — просто взял и вытряхнул весь мешок к ебеням. Пустота.

А вот тут начинается магия, ради которой всё и затевалось. Теоретико-множественные операции, ёба! Это когда у тебя два таких мешка.

a = {1, 2, 3, 4}  # Мой первый мешок с цифрами
b = {3, 4, 5, 6}  # А вот и второй, наглый такой

union = a | b           # {1, 2, 3, 4, 5, 6} — просто свалил всё из обоих мешков в одну кучу (объединение).
intersection = a & b     # {3, 4} — оставил только то, что валялось в *обоих* мешках (пересечение).
difference = a - b       # {1, 2} — выкинул из своего мешка `a` всё, что было в мешке у того парня `b` (разность).
sym_diff = a ^ b         # {1, 2, 5, 6} — оставил только уникальное барахло, которого не было в другом мешке (симметрическая разность).

# А есть ещё методы, которые не новый мешок создают, а твой старый прямо на месте меняют. Жёстко.
a.update(b)             # Это как `a |= b`. Взял и добавил в свой мешок `a` всё, что было в `b`.
a.intersection_update(b)# А это `a &= b`. Вытряхнул из своего мешка всё, чего нет в мешке `b`. Жестоко, но эффективно.

Проверки, которые спасают жизнь:

a = {1, 2}
b = {1, 2, 3}
print(a <= b)           # True. Мешок `a` — это как бы часть мешка `b` (подмножество). Всё из `a` есть в `b`.
print(b >= a)           # True. Обратная история — `b` содержит в себе весь `a` (надмножество).
print(a.isdisjoint({5, 6})) # True. А вот эти два мешка вообще не пересекаются, у них общих элементов — ноль.

Где эту хрень применять? Да везде!

  1. Убрать дубликаты из списка — это святое. unique_list = list(set(duplicate_list)). Правда, порядок может поехать, имей в виду.
  2. Быстро проверить, есть ли элемент в коллекции. element in set — это, блядь, в разы быстрее, чем element in list, особенно когда элементов — овердохуища.
  3. Найти что-то общее или разное. Например, общие друзья в соцсетях у двух людей — это же просто friends_vasya & friends_petya.
  4. Просто для красоты и правильной логики, когда тебе по смыслу нужен именно набор уникальных сущностей.

НО! Есть важный подвох, про который все в начале забывают. В этот мешок можно кидать только неизменяемые (хешируемые) штуки. Цифры, строки, кортежи (если они сами из неизменяемого) — пожалуйста. А вот списки, словари или другие множества — ни-ни, питон тебе мозги выест ошибкой. Запомни это, и будет тебе счастье.