Множества

В математике есть такое понятие как множество (или теория множеств). Возможно вы их даже изучали в курсе математики. Может быть, вы даже знакомы с диаграммами Венна.
На практике множество можно рассматривать просто как четко определенный набор отдельных объектов, которые называются элементами или членами.
Группировка объектов в множество может быть полезна в программировании, и Python представляет нам для этого встроенный тип set.

Множества (тип set) отличаются от других типов объектов уникальными операциями, которые можно с ними выполнять.

Встроенный тип set в Python имеет следующие характеристики:
  • элементы множества неупорядочены (это значит, что два множества эквивалентны, если содержат одинаковые элементы). Хранятся элементы множества не последовательно, а по определенным алгоритмам, которые позволяют быстро определять принадлежность элемента множеству (без перебора всех элементов);
  • элементы множества уникальны. Повторяющиеся элементы не допускаются;
  • множества изменяемы (например, можно добавить элемент в множество), но сами элементы внутри множества должны быть неизменяемые (числа, строки, кортежи). Вы не можете сделать элементом множества список или другое множество;

 

Создание множества
1 способ

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

x = {"school", "teacher", "class", student}
 

2 способ 
Используйте встроенную функцию set().
x = set()    # пустое множество
list_name = ["Andry", "Bob", "Caroline"]
y = set(list_name)    # можно создать множество 
                      # из любого итерируемого объекта
z = set(["Andry", "Bob", "Caroline"])     # {'Bob', 'Caroline', 'Andry'}
k = set(("Andry", "Bob", "Caroline"))     # {'Bob', 'Caroline', 'Andry'}
s = "string s"
m = set(s)    # {'i', 't', 'g', 'r', 'n', 's', ' '} - 
              # обратите внимание! 
              # порядок элементов может быть любой,
              # элементы не повторяются
n = {42, 'foo', 3.14159, None, (1, 2, 3)}    # элементы в наборе  
                                             # могут быть разного типа
 
Вывод множества
Выводятся элементы множества в произвольном порядке, не обязательно в том, в котором они добавляются.
z = set(["Andry", "Bob", "Caroline"]) 
print(z)     # {'Bob', 'Caroline', 'Andry'}
print(*z)    # Bob Andry Caroline

Методы работы с множествами


Количество элементов в множестве
Метод len() возвращает количество элементов в множестве.
k = {42, 'foo', 3.14159, None, (1, 2, 3)} 
print(len(k))    # 5

 

Определение, есть ли элемент в множестве (оператор принадлежности in)
k = {42, 'foo', 3.14159, None, (1, 2, 3)} 
print(42 in k)    # True
print(2 in k)     # False

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

 

Добавление элемента ко множеству
x.add(<elem>)
ко множеству  x добавляет <elem>, который должен быть единственным неизменяемым объектом.

 

Удаление элемента из множества
1) x.remove(<elem>)
удаляется <elem> из множества x. Python вызывает исключение (ошибка), если <elem> нет в x.

2) x.discard(<elem>)
то же удаляет, но в случае отсутствия элемента в множестве не вызывает исключения.

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

4) x.clear()
удаляет все элементы из множества (очищает множество).

Работа с множествами


Многие операции, которые можно использовать для других составных типов (например, списки, кортежи), не имеют смысла для множества.
Например, обращение по индексу и срезы. Однако Python позволяет выполнять ряд операций с элементами множества, которые имитируют операции с математическими множествами.
Большинство из этих операций можно выполнять двумя способами: операцией или определенным методом.


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

x1 = {'foo', 'bar', 'baz'}
x2 = {'baz', 'qux', 'quux'}
print(x1 | x2)         # {'bar', 'baz', 'qux', 'quux', 'foo'}
print(x1.union(x2))    # {'bar', 'baz', 'qux', 'quux', 'foo'}

Операция объединения множеств (|) и аналогичный метод имеют тонкую разницу. Когда вы используете | оператор, оба операнда должны иметь тип set. Метод union() примет любой итерируемый объект в качестве аргумента, преобразует его во множество и затем выполнит объединение.
 
Примечание
Итерируемый объект (iterable) - это объект, который способен возвращать элементы по одному. 


Обратите внимание на разницу
x1 = {'foo', 'bar', 'baz'} 
print(x1.union(('baz', 'qux', 'quux')))    # {'baz', 'bar', 'quux', 'foo', 'qux'}
print(x1 | ('baz', 'qux', 'quux'))         # builtins.TypeError: 
                                           # unsupported operand type(s) for |: 'set' and 'tuple'



Операции и методы для множеств

Ниже приведен список операций, доступных в Python. Некоторые выполняются оператором, некоторые - методом, а некоторые - обоими. Принцип, изложенный выше, обычно применяется: там, где ожидается множество, методы обычно принимают любой итерируемый элемент в качестве аргумента, но операторы требуют в качестве операндов объекты типа set.

Пояснение: записи в квадратных скобках указывают на то, что эта часть может быть опущена.
 
Название Метод Оператор Описание
объединение x1.union(x2[, x3, …]) x1 | x2 [| x3 …] возвращает множество всех элементов, которые присутствуют либо в x1 либо в x2 (либо других)
пересечение множеств x1.intersection(x2[, x3, …]) x1 & x2 [& x3 …] возвращает множество элементов, общих для x1 и x2 (и других)
разница между множествами x1.difference(x2) x1 - x2 [- x3 …] возвращает множество элементов, которые есть в x1, но нет в x2 (только -  поддерживает множественность)
симметричная разница между множествами x1.symmetric_difference(x2) x1 ^ x2 [^ x3] возвращает множество элементов, которые есть в x1 или x2, но не в обоих сразу
(оператор ^ поддерживает множественность)
общие элементы в наборах x1.isdisjoint(x2) нет возвращает True, если x1 и x2 не имеют общих элементов
x1 подмножество x2 x1.issubset(x2) x1 <= x2 True, если x1 подмножество x2, иначе - False
Правильное подмножество - x1 < x2 True, если x1 является правильным подмножеством x2
x1 надмножество x2 x1.issuperset(x2) x1 >= x2 True, если x1 содержит все элементы x2
правильное надмножество - x1 > x2 True, если x1 является правильным надмножеством x2
объединение множеств x1.update(x2[, x3 ...]) x1 |= x2 [| x3 ...] Добавляет к x1 элементы x2, которых нет в x1
пересечение множеств x1.intersection_update(x2[, x3 ...]) x1 &= x2 [& x3 ...] Обновляет x1, сохраняя элементы, которые есть в обоих множествах x1 и x2
разница множеств x1.difference_update(x2[, x3 ...]) x1 -= x2 [| x3 ...] Обновляет x1, удаляя элементы, найденные в x2
симметричная разность x1.symmetric_difference_update(x2) x1 ^= x2 Обновляет x1, сохраняя элементы, найденные в x1 ли x2, но не в обоих

Сортировка множеств?

Как мы знаем, порядок следования элементов в множестве не учитывается. Поэтому есть ли смысл говорить о сортировке множеств в Python 3?! (Именно поэтому в заголовке стоит знак вопроса)

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

Рассмотрим несколько примеров. Что будет с элементами разных типов данных в одном множестве? Такие элементы не должны сортироваться. Если мы будем выводить элементы с помощью команды print(), то они выводятся примерно следующим образом:

a = {0, 1, 12, 'b', 'ab', 3, 2, 'a'}
print(a)    # {0, 1, 2, 3, 'a', 12, 'b', 'ab'}
В данном случае выводятся не отсортированные значения. Если повторить запуск, то порядок вывода может быть уже другой. Но это только в том случае, если перемешаны элементы разного типа.

Давайте попытаемся вывести данные одного типа (например, только числа):
a = {0, 1, 12, 3, 2}
print(a)    # {0, 1, 2, 3, 12}
Все элементы выведены упорядоченно. Попробуем преобразовать в список:
a = {0, 1, 12, 3, 2}
b = list(a)
print(b)    # [0, 1, 2, 3, 12]
Аналогично, в список записались отсортированные по возрастанию элементы.

Получается, что элементы хранятся в памяти в упорядоченном виде, если они одного типа. Но лучше не стоит на это рассчитывать, алгоритмы Python могут поменяться.

Если вам нужно получить отсортированный список из множества, лучше воспользоваться для верности функцией sort (sorted). Элементы будут точно отсортированы. Ваш код будет понятен для других.