Простой Python — страница 10 из 66

Множество похоже на словарь, значения которого опущены. Он имеет только ключи. Как и в случае со словарем, ключи должны быть уникальны. Если вам нужно прикрепить к ключу некую информацию, воспользуйтесь словарем.

Раньше кое-где теорию множеств преподавали в начальной школе наряду с основами математики. Если в вашей школе такого не было (или было, но вы в это время смотрели в окно, как и я), на рис. 3.1 можете увидеть объединения и пересечения множеств.

Предположим, вы хотите объединить два множества, которые содержат несколько общих ключей. Поскольку множество должно содержать только уникальные значения, объединение двух множеств будет содержать лишь одно включение каждого ключа. Пустое множество — это множество, содержащее ноль элементов. Основываясь на рис. 3.1, можно сказать, что пустым будет множество, которое содержит женские имена, начинающиеся с буквы «Х».


Рис. 3.1. Распространенные операции с множествами

Создание множества с помощью функции set()

Чтобы создать множество, вам следует использовать функцию set() или разместить в фигурных скобках одно или несколько разделенных запятыми значений, как показано здесь:

>>> empty_set = set()

>>> empty_set

set()

>>> even_numbers = {0, 2, 4, 6, 8}

>>> even_numbers

{0, 8, 2, 4, 6}

>>> odd_numbers = {1, 3, 5, 7, 9}

>>> odd_numbers

{9, 3, 1, 5, 7}

Как и в случае со словарем, порядок ключей в множестве не имеет значения.


Поскольку пустые квадратные скобки [] создают пустой список, вы могли бы рассчитывать на то, что пустые фигурные скобки {} создают пустое множество. Вместо этого пустые фигурные скобки создают пустой словарь. Именно поэтому интерпретатор выводит пустое множество как set() вместо {}. Почему так происходит? Словари появились в Python раньше и успели захватить фигурные скобки в свое распоряжение.

Преобразование других типов данных с помощью функции set()

Вы можете создать множество из списка, строки, кортежа или словаря, потеряв все повторяющиеся значения.

Для начала взглянем на строку, которая содержит более чем одно включение некоторых букв:

>>> set('letters')

{'l', 'e', 't', 'r', 's'}

Обратите внимание на то, что множество содержит только одно включение букв «e» или «t», несмотря на то, что в слове letters по два включения каждой из них.

Создадим множество из списка:

>>> set(['Dasher', 'Dancer', 'Prancer', 'Mason-Dixon'])

{'Dancer', 'Dasher', 'Prancer', 'Mason-Dixon'}

А теперь из кортежа:

>>> set(('Ummagumma', 'Echoes', 'Atom Heart Mother'))

{'Ummagumma', 'Atom Heart Mother', 'Echoes'}

Когда вы передаете функции set() словарь, она возвращает только ключи:

>>> set({'apple': 'red', 'orange': 'orange', 'cherry': 'red'})

{'apple', 'cherry', 'orange'}

Проверяем на наличие значения с помощью ключевого слова in

Такое использование множеств самое распространенное. Мы создадим словарь, который называется drinks. Каждый ключ будет названием коктейля, а соответствующие значения — множествами ингредиентов:

>>> drinks = {

…·····'martini': {'vodka', 'vermouth'},

…·····'black russian': {'vodka', 'kahlua'},

…·····'white russian': {'cream', 'kahlua', 'vodka'},

…·····'manhattan': {'rye', 'vermouth', 'bitters'},

…·····'screwdriver': {'orange juice', 'vodka'}

…·····}

Несмотря на то что и словарь, и множества окружены фигурными скобками ({ и }), множество — это всего лишь последовательность значений, а словарь — это набор пар «ключ — значение».

Какой из коктейлей содержит в себе водку? (Обратите внимание на то, что для выполнения этих проверок я заранее демонстрирую использование ключевых слов for, if, and и or, которые будут рассмотрены только в следующей главе.)

>>> for name, contents in drinks.items():

…·····if 'vodka' in contents:

…·········print(name)

screwdriver

martini

black russian

white russian

Мы хотим выпить коктейль с водкой, но не переносим лактозу, а вермут на вкус напоминает керосин:

>>> for name, contents in drinks.items():

…·····if 'vodka' in contents and not ('vermouth' in contents or

…·········'cream' in contents):

…·········print(name)

screwdriver

black russian

Перепишем этот пример чуть более сжато в следующем разделе.

Комбинации и операторы

Что, если вам нужно проверить наличие сразу нескольких значений множества? Предположим, вы хотите найти любой напиток, содержащий апельсиновый сок или вермут. Для этого мы используем оператор пересечения множеств (&):

>>> for name, contents in drinks.items():

…·····if contents & {'vermouth', 'orange juice'}:

…·········print(name)

screwdriver

martini

manhattan

Результатом работы оператора & является множество, содержащее все элементы, которые находятся в обоих сравниваемых списках. Если ни один из заданных ингредиентов не содержится в предлагаемых коктейлях, оператор & вернет пустое множество. Этот результат можно считать равным False.

Теперь перепишем пример из предыдущего раздела, в котором мы хотели водки, не смешанной со сливками или вермутом:

>>> for name, contents in drinks.items():

…·····if 'vodka' in contents and not contents & {'vermouth', 'cream'}:

…·········print(name)

screwdriver

black russian

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

>>> bruss = drinks['black russian']

>>> wruss = drinks['white russian']

В следующих примерах демонстрируется использование операторов множеств. В одних из них демонстрируется применение особой пунктуации, в других — особых функций, в третьих — и того и другого. Мы будем использовать тестовые множества а (содержит элементы 1 и 2) и b (содержит элементы 2 и 3):

>>> a = {1, 2}

>>> b = {2, 3}

Пересечение множеств (члены обоих множеств) можно получить с помощью особого пунктуационного символа & или функции множества intersection(), как показано здесь:

>>> a & b

{2}

>>> a.intersection(b)

{2}

В этом фрагменте используются сохраненные нами переменные:

>>> bruss & wruss

{'kahlua', 'vodka'}

В этом примере мы получаем объединение (члены обоих множеств), используя оператор | или функцию множества union():

>>> a | b

{1, 2, 3}

>>> a.union(b)

{1, 2, 3}

Алкогольная версия:

>>> bruss | wruss

{'cream', 'kahlua', 'vodka'}

Разность множеств (члены только первого множества, но не второго) можно получить с помощью символа — или функции difference():

>>> a — b

{1}

>>> a.difference(b)

{1}

>>> bruss — wruss

set()

>>> wruss — bruss

{'cream'}

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

Для выполнения исключающего ИЛИ (элементы или первого, или второго множества, но не общие) используйте оператор ^ или функцию symmetric_difference():

>>> a ^ b

{1, 3}

>>> a.symmetric_difference(b)

{1, 3}

В этом примере определяется эксклюзивный ингредиент для русских напитков:

>>> bruss ^ wruss

{'cream'}

Вы можете проверить, является ли одно множество подмножеством другого (все члены первого множества являются членами второго), с помощью оператора <= или функции issubset():

>>> a <= b

False

>>> a.issubset(b)

False

Добавление сливок в коктейль «черный русский» сделает его «белым русским», поэтому wruss является подмножеством bruss:

>>> bruss <= wruss

True

Является ли любое множество подмножеством самого себя? Ага.

>>> a <= a

True

>>> a.issubset(a)

True

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

>>> a < b

False

>>> a < a

False

>>> bruss < wruss

True

Множество множеств противоположно подмножеству (все члены второго множества являются также членами первого). Для определения этого используется оператор >= или функция issuperset():

>>> a >= b

False

>>> a.issuperset(b)

False

>>> wruss >= bruss

True

Любое множество является множеством множеств самого себя:

>>> a >= a

True

>>> a.issuperset(a)

True

И наконец, вы можете найти собственное множество множеств (первое множество содержит все члены второго и несколько других) с помощью оператора >:

>>> a > b

False

>>> wruss > bruss

True

Множество не может быть собственным множеством множеств самого себя:

>>> a > a

False

Сравнение структур данных