Перейти до змісту

Множини в Python

Множина – невпорядкована колекція об'єктів, що хешуються, які не повторюються.

Типове використання множин — перевірка певного елемента на входження в множину та видалення повторів елементів і виконання таких операцій, як об'єднання, пересічення, різниця і симетрична різниця.

В множинах немає поняття позиції елемента. Відповідно, вони не підтримують індексацію і зрізання.

Вбудованими в Python класами множин є:

  • set (мутабельна множина).
  • frozenset (немутабельна множина)

Створення множин

Створити множини в Python можна декількома способами.

Перерахування елементів (тільки set)

Найпростіший спосіб — просто перерахувати елементи, які будуть складати множину. Елементи розділяються знаком коми і заключаються у фігурні дужки:

>>> my_set = {1, 5, 3, 9}  # множина цілих чисел
>>> my_set
{1, 3, 5, 9}
>>> fruits = {'apple', 'orange', 'apple', 'orange', 'banana'}  # множина символьних рядків, тільки унікальні елементи
>>> fruits
{'orange', 'banana', 'apple'}
>>>

Зауважте: таким способом можна створити тільки об'єкти класа set!

Включення множин (тільки set)

Множину можна створити за допомогою включень множин. Синтаксис дуже схожий на спискові включенні, різниця тільки у тому, що вираз заключається у фігурні дужки:

>>> number_set = {x*x for x in range(10) if x%2}
>>> number_set
{1, 9, 81, 49, 25}
>>>
>>> number_set = {i * j for i in range(3) for j in range(3)}
>>> number_set
{0, 1, 2, 4}
>>>

Зауважте: таким способом можна створити тільки об'єкти класа set!

Створення за допомогою конструктора класа

Для початку створимо пусту множину, тобто таку, яка не містить жодного об'єкта:

>>> empty_set = set()
>>> empty_set
set()
>>> empty_frozenset = frozenset()
>>> empty_frozenset
frozenset()
>>>

Конструктору множини можна передати ітерабельний об'єкт:

>>> my_frozenset = frozenset([4, 1, 4, 3, 8])
>>> my_frozenset
frozenset({8, 1, 3, 4})
>>>
>>> letters = set('abrakadabra')
>>> letters
{'b', 'd', 'r', 'k', 'a'}
>>>

Множини у свою чергу теж є ітерабельними об'єктами:

>>> my_set = set(my_frozenset)
>>> my_set
{8, 1, 3, 4}
>>>

Давайте спробуємо створити множину передавши в конструктор генератор:

>>> def get_ints(n):
...     for i in range(n):
...         yield i
...         yield i + 1
...
>>> list(get_ints(10))  # усі числа, які повертає генератор
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10]
>>> set(get_ints(10))   # множина містить тільки унікальні значенння
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
>>>

Операції з множинами

Операція Опис
len(s) Кількість елементів множини
x in s
x not in s
Перевірка чи входить об'єкт у множину
s.isdisjoint(t) Перевірка того, що множина s не має спільних елементів з множиною t
s.issubset(t)
s <= t
Перевірка того, що усі елементи множини s є елементами множини t
s < t Перевірка того, що s<=t і s!=t
s.isuperset(t)
s >= t
Перевірка того, що усі елементи множини t є елементами множини s
s > t Перевірка того, що s>=t і `s!=t
s.union(t, …)
s | t | …
створення нової множини, яка є об'єднанням даних множин
s.intersection(t, …)
s & t & …
створення нової множини, яка є перетином даних множин
s.difference(t, …)
s - t - …
створення нової множини, яка є різницею даних множин
s.symmetric_difference(t)
s ^ t
створення нової множини, яка є симетричною різницею даних множин
s.copy() Неповна копія множини s

Як ви могли зауважити, що одні й ті ж операції можна викликати як бінарний оператор, так і як метод класа. Різниця полягає у наступному:

  • операції над множинами, що є методами, приймають у якості аргументів будь-які ітерабельні об'єкти
  • операції, які записані у вигляді бінарних операцій, потребують щоб другий операнд теж був множиною, і повертає множину того типу, якою була перша множина

Наступні операції використовуються тільки з мутабельними множинами:

Операція Опис
s.update(t, …)
s |= t | …
додати до даної множини елементи з інших множин
s.intersection_update(t, …)
s &= t & …
залишити у даній множині тільки ті елементи, що є і в інших множинах
s.difference_update(t, …)
s -= t | …
видалити з даної множини ті елементи, що є в інших множинах
s.symmetric_difference_update(t)
s ^= t
залишити або додати в s елементи, що є або в s, або в t, але не в обох множинах
s.add(element) додати новий елемент у множину
s.remove(element) Видалити елемент з множини. Якщо елемента у множині немає, піднімається виняток KeyError
s.discard(element) Видалити елемент з множини якщо він належить цій множині
s.pop() Видалити з множини і повернути довільний елемент. Якщо множина пуста, піднімається виняток KeyError
s.clear() Видалити усі елементи з множини

Розглянемо деякі операції з множинами.

Зміна множини

Метод add() приймає один аргумент будь-якого немутабельного типу і додає його в множину.

>>> a_set = {1, 2} 
>>> a_set.add(4) 
>>> a_set
{1, 2, 4}
>>> len(a_set) # Тепер множина містить три елементи. 
3

Якщо ви спробуєте додати до множини елемент, який там вже був, нічого не станеться. Не відбудеться ніякої помилки, і нічого не зміниться. Множина і далі міститиме три елементи.

Метод update() приймає множину і додає всі елементи цієї множини до нашої. Це те ж саме, що викликати add() для кожного елемента множини-параметра:

>>> a_set = {1, 2, 3} 
>>> a_set
{1, 2, 3} 
>>> a_set.update({2, 4, 6})

Також update() можна викликати з довільним числом параметрів, це те ж саме, що викликати цей метод послідовно для кожного з них окремо:

>>> a_set.update({3, 6, 9}, {1, 2, 3, 5, 8, 13}) 
>>> a_set
{1, 2, 3, 4, 5, 6, 8, 9, 13}

Окрім множин, update() можна передати ітерабельний об'єкт:

>>> a_set.update([10, 20, 30]) 
>>> a_set
{1, 2, 3, 4, 5, 6, 8, 9, 10, 13, 20, 30}

Видалення елементів з множини

Метод discard() приймає єдине значення як параметр, і видаляє це значення з множини. Якщо викликати discard() для значення, якого немає в множині, в ній нічого не зміниться. Не згенерується жодного винятку:

>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} 
>>> a_set
{1, 3, 36, 6, 10, 45, 15, 21, 28} 
>>> a_set.discard(10) 
>>> a_set
{1, 3, 36, 6, 45, 15, 21, 28}
>>> a_set.discard(10) 
>>> a_set
{1, 3, 36, 6, 45, 15, 21, 28}

Метод remove() також приймає єдине значення як аргумент, і також видаляє це значення з множини. Якщо значення немає в множині, метод remove() кидає виняток KeyError:

>>> a_set.remove(21) 
>>> a_set
{1, 3, 36, 6, 45, 15, 28}
>>> a_set.remove(21)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 21

Метод pop() видаляє одне значення з множини і повертає його. Щоправда, оскільки множини - це невпорядковані набори, то "останнього" немає елемента — важко передбачити, який елемент буде повернуто. Спроба виклику pop() для порожньої множини створить виняток KeyError:

>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} 
>>> a_set.pop()
1 
>>> a_set.pop()
3 
>>> a_set.pop()
36 
>>> a_set
{6, 10, 45, 15, 21, 28}
>>> a_set.pop()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'pop from an empty set'

Метод clear() видаляє всі значення множини, роблячи її порожньою:

>>> a_set.clear() 
>>> a_set
set()

Теоретико-множинні операції

Розділ названо так тому, що зараз ми розглянемо ті дії з множинами, які вивчає відповідний розділ математики.

Щоб визначити, чи належить множині елемент, використовуйте оператор in/not in:

>>> a_set = {2, 4, 5, 9, 12, 21, 30, 51, 76, 127, 195} 
>>> 30 in a_set
True 
>>> 31 in a_set
False

Метод union() (об’єднання) повертає множину, що складається з елементів, які належать хоча б одній з двох множин:

>>> {1,2,3}.union([3,4,5])
{1, 2, 3, 4, 5}
>>>

Метод intersection() (перетин) повертає множину, що складається з елементів, які належать одночасно двом множинам:

>>> {1,2,3}.intersection([2,3,4])
{2, 3}
>>>

Метод difference() (різниця) повертає множину з тих елементів, які не належать переданій множині:

>>> {1,2,3,4,5}.difference([2,3,11])
{1, 4, 5}
>>>

Метод symmetric_difference (симетрична різниця) повертає множину з тих елементів, які належать рівно одній з множин:

>>> {1,2,3,4,5}.symmetric_difference([2,3,11])
{1, 4, 5, 11}
>>>

Множини в булевому контексті

Тут, як завжди, все просто: порожня множина — False, а непорожня, не залежно від вмісту елементів — True.

Back to top