Поэлементно сравнить коллекции в Python

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

Конечно, это не единственная возможность. Множества в питоне идеально подходят, чтобы поэлементно сравнивать коллекции.

Допустим, мы ведем учет посетителей:

jan = ["Питер", "Клер", "Френк"]
feb = ["Френк", "Зоя", "Дуглас"]
mar = ["Клер", "Питер", "Зоя"]

И хотим узнать, кто приходил в январе и феврале. Нет ни малейшего желания писать вложенный цикл с перебором jan и feb. Намного приятнее (и быстрее) использовать множества.

jan = {"Питер", "Клер", "Френк"}
feb = {"Френк", "Зоя", "Дуглас"}
mar = {"Клер", "Питер", "Зоя"}

Были в январе и феврале:

>>> jan & feb
{'Френк'}

В январе или марте:

>>> jan | mar
{'Питер', 'Клер', 'Зоя', 'Френк'}

В феврале, но не в марте:

>>> feb - mar
{'Френк', 'Дуглас'}

В январе или феврале, но не в оба месяца:

>>> jan ^ feb
{'Питер', 'Клер', 'Зоя', 'Дуглас'}

Вернулись ли зимние посетители в марте?

>>> (jan & feb) <= mar
False

Все эти операции выполняются за линейное время O(n) вместо квадратичного O(n²), как было бы на списках.

Кроме обычных множеств бывают замороженные (их нельзя менять):

>>> visitors = frozenset ().union (jan, feb, mar)
>>> visitors
frozenset ({'Питер', 'Клер', 'Зоя', 'Френк', 'Дуглас'})

Множество можно слепить из любого iterable-типа. Например, из строки:

>>> frozenset ('abcde')
frozenset ({'b', 'd', 'e', 'c', 'a'})

Или даже из диапазона:

>>> set (range (1, 10))
{1, 2, 3, 4, 5, 6, 7, 8, 9}

Ключи словаря тоже работают как множество:

>>> stats = { "Френк": 99, "Клер": 50 }
>>> stats.keys() & jan
{'Клер', 'Френк'}

В общем, полезная штука.

Заметка из телеграм-канала «Oh My Py»