Чем отличаются set и frozenset python
Перейти к содержимому

Чем отличаются set и frozenset python

  • автор:

Чем отличаются set и frozenset python

[Коллекции] Множества set и frozenset в Python: примеры и использование

[Коллекции] Множества set и frozenset в Python: примеры и использование

21 марта 2023
Оценки статьи
Еще никто не оценил статью

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

Создание множеств в Python

В Python множества создаются с помощью фигурных скобок <> , содержащих уникальные элементы, разделенные запятыми. Например:

# Создание множества my_set = 1, 2, 3, 4, 5> print(my_set) # 

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

# Создание пустого множества empty_set = set() print(empty_set) # set() 

Основные операции с множествами в Python

В Python множества поддерживают множество операций, таких как объединение, пересечение, разность и симметрическая разность.

Ниже показаны часто используемые из методов:

Объединение множеств: оператор | или метод union() .

A = 1, 2, 3> B = 3, 4, 5> C = A | B print(C) # выведет 

Пересечение множеств: оператор & или метод intersection() .

A = 1, 2, 3> B = 3, 4, 5> C = A & B print(C) # выведет 

Разность множеств: оператор — или метод difference() .

A = 1, 2, 3> B = 3, 4, 5> C = A - B print(C) # выведет 

Симметрическая разность множеств: оператор ^ или метод symmetric_difference() .

A = 1, 2, 3> B = 3, 4, 5> C = A ^ B print(C) # выведет 

Примеры использования set в Python

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

numbers = [1, 2, 3, 3, 4, 5, 5, 6] unique_numbers = set(numbers) print(unique_numbers) # 

Пример 2: Операции с множествами

set1 = 1, 2, 3, 4, 5> set2 = 4, 5, 6, 7, 8>  # Объединение множеств print(set1.union(set2)) # # Пересечение множеств print(set1.intersection(set2)) # # Разность множеств print(set1.difference(set2)) # # Симметрическая разность множеств print(set1.symmetric_difference(set2)) # 

Пример 3: Добавление и удаление элементов

fruits = "apple", "banana", "orange">  # Добавление элемента fruits.add("grape") print(fruits) # # Удаление элемента fruits.remove("banana") print(fruits) # 

Создание неизменяемого множества (frozenset) в Python

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

fruits = frozenset(["apple", "banana", "cherry"]) 

Основные отличия frozenset от set заключаются в том, что frozenset не может быть изменен после создания, включая добавление, удаление и изменение элементов. Поэтому, frozenset может быть использован в качестве ключа словаря, а set нет.

Примеры использования frozenset в Python

Пример 1: Создание и доступ к элементам frozenset

fruits = frozenset(["apple", "banana", "cherry"]) print(fruits) # Output: frozenset()  # Доступ к элементам frozenset for fruit in fruits:  print(fruit) # Output: # apple # banana # cherry 

Пример 2: Сравнение frozenset с set

fruits1 = frozenset(["apple", "banana", "cherry"]) fruits2 = set(["banana", "cherry", "orange"])  # Проверяем, содержится ли fruits1 в fruits2 print(fruits1.issubset(fruits2)) # Output: False  # Объединяем два множества fruits3 = fruits1.union(fruits2) print(fruits3) # Output: frozenset() 

Пример 3: Ключи словаря

fruit_counts = frozenset(["apple", "banana"]): 2, frozenset(["cherry"]): 3> print(fruit_counts) # Output: ): 2, frozenset(): 3> 

Таким образом, frozenset является неизменяемым аналогом set. Это может быть полезно, когда нужно использовать множество в качестве ключа словаря или когда необходимо сохранить множество в неизменяемом состоянии.

Заключение

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

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

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

Оба типа множеств имеют свои особенности и применяются в разных ситуациях. Важно выбирать правильный тип множества для конкретной задачи.

Меню категорий

    Загрузка категорий.

Python: Set/Frozenset (Множество)

Множество (класс set) — это контейнер, который содержит уникальные не повторяющиеся элементы в случайном порядке (неупорядоченная коллекция).

Что значит неупорядоченная? Это значит, что два множества эквивалентны, если содержат одинаковые элементы.

Set

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

Set

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

 mySet = # выводится в любом случайном порядке print(mySet) #

Но таким способом нельзя создать пустое множество, вместо него будет создан пустой словарь.

 wrong_empty_set = <> print(type(wrong_empty_set)) #

Для создания пустого множества нужно непосредственно использовать set():

 correct_empty_set = set() print(type(correct_empty_set)) #

Также в set() можно передать какой-либо объект, по которому можно пройтись (Iterable):

 color_list = ["red", "green", "green", "blue", "purple", "purple"] color_set = set(color_list) print(color_set) # порядок может быть другим #

Число элементов вычисляется через len().

Существует ограничение, что элементами множества (как и ключами словарей) в Python могут быть только так называемые хешируемые (Hashable) объекты. Это обусловлено тем фактом, что внутренняя реализация set основана на хеш-таблицах. Например, списки и словари – это изменяемые объекты, которые не могут быть элементами множеств. Большинство неизменяемых типов в Python (int, float, str, bool, и т.д.) – хешируемые. Неизменяемые коллекции, например tuple, являются хешируемыми, если хешируемы все их элементы.

Проверить принадлежит ли какой-либо объект множеству можно с помощью оператора in.

 tremendously_huge_set = if "green" in tremendously_huge_set: print("Green is there!") else: print("Unfortunately, there is no green. ") 

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

 words = ['a', 'a', 'b', 'b', 'c', 'd', 'e'] mySet = set(words) print(str(mySet)) 
 colors = for color in colors: print(color) 

Два множества называются равными, если они состоят из одних и тех же элементов, порядок этих элементов не важен. Обратите внимание, что состав множеств отличается, но тем не менее они одинаковы (см. начало статьи).

Equal sets

 my_cats = your_cats = print(my_cats == your_cats) # True 

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

Set

 even_numbers = odd_numbers = # Очевидно, что множества чётных и нечётных чисел не пересекаются if even_numbers.isdisjoint(odd_numbers): print("Множества не пересекаются!") # Множества не пересекаются! 

Подмножество множества S – это такое множество, каждый элемент которого является также и элементом множества S. Множество S в свою очередь является надмножеством исходного множества.

Set

 # Множество чисел Фибоначчи меньших 100 fibonacci_numbers = # Множество натуральных чисел меньших 100 natural_numbers = set(range(100)) # Множество чисел Фибоначчи является подмножеством множества # натуральных чисел if fibonacci_numbers.issubset(natural_numbers): print("Подмножество!") # Вывод: Подмножество! # В свою очередь множество натуральных чисел является # надмножеством множества чисел Фибоначчи if natural_numbers.issuperset(fibonacci_numbers): print("Надмножество!") # Вывод: Надмножество! 

Пустое множество является подмножеством абсолютно любого множества. Само множество является подмножеством самого себя.

Другие методы: ‘clear’ (очистка множества), ‘copy’, ‘pop’ (удаляет первый элемент из множества. Так как множества не упорядочены, нельзя точно сказать, какой элемент будет первым), ‘remove’, ‘update’, ‘__bases__’, ‘__contains__’, ‘add’, ‘difference’, ‘difference_update’, ‘discard’, ‘intersection’ (пересечение), ‘intersection_update’, ‘isdisjoint’ (истина, если set и other не имеют общих элементов), ‘issubset’, ‘issuperset’, ‘symmetric_difference’, ‘symmetric_difference_update’, ‘union’ (объединение нескольких множеств).

У множеств можно находить объединение или пересечение элементов.

Объединение множеств – это множество, которое содержит все элементы исходных множеств. В Python есть несколько способов объединить множества.

Set

 my_fruits = your_fruits = # Для объединения множеств можно использовать оператор `|`, # оба операнда должны быть объектами типа set our_fruits = my_fruits | your_fruits print(our_fruits) # Вывод (порядок может быть другим): # Также можно использовать метод union. # Отличие состоит в том, что метод union принимает не только # объект типа set, а любой iterable-объект you_fruit_list: list = list(your_fruits) our_fruits: set = my_fruits.union(you_fruit_list) print(our_fruits) # Вывод (порядок может быть другим):

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

 colors = # Метод add добавляет новый элемент в множество colors.add("purple") # Добавление элемента, который уже есть в множестве, не изменяет # это множество colors.add("red") print(colors) # Вывод (порядок может быть другим): # Метод update принимает iterable-объект (список, словарь, генератор и т.п.) # и добавляет все элементы в множество numbers = numbers.update(i**2 for i in [1, 2, 3]) print(numbers) # Вывод (порядок может быть другим):

Пересечение множеств – это множество, в котором находятся только те элементы, которые принадлежат исходным множествам одновременно.

Set

 def is_prime(number: int) -> bool: """ Возвращает True, если number - это простое число """ assert number > 1 return all(number % i for i in range(2, int(number**0.5) + 1)) def is_fibonacci(number: int) -> bool: """ Возвращает True, если number - это число Фибоначчи """ assert number > 1 a, b = 0, 1 while a + b

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

Set

 i_know: set = you_know: dict = < "Go": 0.4, "C++": 0.6, "Rust": 0.2, "Java": 0.9 ># Обратите внимание, что оператор `-` работает только # для объектов типа set you_know_but_i_dont = set(you_know) - i_know print(you_know_but_i_dont) # Вывод (порядок может быть другим): # Метод difference может работать с любым iterable-объектом, # каким является dict, например i_know_but_you_dont = i_know.difference(you_know) print(i_know_but_you_dont) # Вывод:

Удаление элемента из множества можно рассматривать как частный случай разности, где удаляемый элемент – это одноэлементное множество. Следует отметить, что удаление элемента, как и в аналогичном случае с добавлением элементов, изменяет исходное множество.

 fruits = # Удаление элемента из множества. Если удаляемого элемента # нет в множестве, то ничего не происходит fruits.discard("orange") fruits.discard("pineapple") print(fruits) # Вывод (порядок может быть другим): # Метод remove работает аналогично discard, но генерирует исключение, # если удаляемого элемента нет в множестве fruits.remove("pineapple") # KeyError: "pineapple" 

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

Set

 non_positive = non_negative = # Обратите внимание, что оператор `^` может применяться # только для объектов типа set non_zero = non_positive ^ non_negative print(non_zero) # Вывод (порядок может быть другим):

Как видно из примера выше, число 0 принадлежит обоим исходным множествам, и поэтому оно не входит в результирующее множество. Для операции симметрической разности, помимо оператора ^, также существует два специальных метода – symmetric_difference и symmetric_difference_update. Оба этих метода принимают iterable-объект в качестве аргумента, отличие же состоит в том, что symmetric_difference возвращает новый объект-множество, в то время как symmetric_difference_update изменяет исходное множество.

 non_positive = non_negative = range(4) non_zero = non_positive.symmetric_difference(non_negative) print(non_zero) # Вывод (порядок может быть другим): # Метод symmetric_difference_update изменяет исходное множество colors = colors.symmetric_difference_update(["green", "blue", "yellow"]) print(colors) # Вывод (порядок может быть другим):

frozenset

frozenset — это неизменяемое множество.

Методы: ‘__name__’, ‘copy’, ‘__bases__’, ‘__contains__’, ‘difference’, ‘intersection’, ‘isdisjoint’, ‘issubset’, ‘issuperset’, ‘symmetric_difference’, ‘union’.

Создадим два разных типа множества, сравним их и попытаемся добавить новые элементы.

 setCat = set('кот') frozenCat = frozenset('кот') print(setCat == frozenCat) print(type(setCat)) # set print(type(frozenCat)) #frozenset setCat.add('э') # можем добавить print(setCat) frozenCat.add('e') # эта строка вызовет ошибку при компиляции 

Изучите структуру данных Python Set/Frozenset – часть 4

В этой Части 4 серии статей о структурах данных Python мы обсудим, что такое набор, чем он отличается от других структур данных в Python, как создавать объекты набора, удалять объекты набора и методы объектов набора. .

  • Объект-множество — это неупорядоченная коллекция различных хешируемых объектов.
  • Set автоматически удаляет повторяющиеся элементы из объекта.
  • Поскольку заданные объекты неупорядочены, операции индексирования и нарезки не поддерживаются.

В настоящее время существует два встроенных типа наборов.

  1. set – поскольку он изменчив, он не имеет хеш-значения и не может использоваться как ключ словаря или как элемент другого набора.
  2. frozenset – неизменяемый и хешируемый – его содержимое нельзя изменить после создания; поэтому его можно использовать как ключ словаря или как элемент другого набора.

Построить объект набора

Создайте набор с помощью метода конструктора “set()” или с помощью фигурных скобок с запятой, разделяющих элементы “”.

ПРИМЕЧАНИЕ. Вы не можете создать объект набора с помощью пустых фигурных скобок, так как это создаст объект словаря.

Установить методы

Используйте встроенную функцию “dir()” для получения списка доступных методов и атрибутов набора.

Добавить элементы для установки объекта

Как уже говорилось, set — это изменяемый тип. Вы можете добавлять, удалять и обновлять объект набора после его создания.

Давайте поговорим о двух методах установки: add и update.

  • метод add(elem) – этот метод добавляет один элемент к заданному объекту.
  • метод update(*others) – этот метод добавляет несколько элементов в заданный объект. Вы можете передавать изменяемые/неизменяемые объекты в качестве аргумента метода обновления.

ПРИМЕЧАНИЕ. Дубликаты будут автоматически удалены.

Удаление/очистка элементов из заданного объекта

Как вы уже видели ранее в других разделах о структурах данных (список, кортежи, словарь), для набора вы также можете использовать встроенное ключевое слово “del” для удаления объекта набора из пространства имен (т. е. Память).

Ниже приведены методы установки объектов для удаления элементов.

  • clear() – очистит все элементы, сделав набор пустым. Этот метод clear() доступен в других структурах данных, обеспечивающих ту же функциональность.
  • pop() – удаляет произвольные элементы.
  • discard(elem) – если элемент не найден в заданном объекте, метод discard() не вызовет никаких ошибок.
  • remove(elem) – то же, что и метод discard(), но вызывает ошибку KeyError, если элемент не найден.

Установить операции

Set предоставляет методы для выполнения математических операций, таких как пересечение, объединение, разность и симметричная разность. Помните «диаграмму Венна» из школьных лет?

Ниже мы рассмотрим методы выполнения математических операций.

  • союз
  • пересечение
  • перекресток_обновление
  • симметричная_разница
  • symmetric_difference_update
  • разница
  • разница_обновление
  • непересекающийся
  • issubset
  • issuperset
Союз, Пересечение, Разница, Симметричная_Разница
  • union(*other) – возвращает новый набор с элементами из набора и всеми остальными.
  • intersection(*other) – возвращает новый набор с элементами, общими для этого набора и всех остальных.
  • difference(*others) – возвращает новый набор с элементами, которых нет в других.
  • symmetric_difference(other) – возвращает новый набор с элементами либо из набора, либо из другого, но не из обоих.

Пересечение_Обновление

intersection_update(*others) — обновить набор, сохранив только найденные в нем элементы и все остальные.

Обновление различий

difference_update(*others) – обновить набор, сохранив только найденные в нем элементы и все остальные.

Symmetric_Difference_Update

symmetric_difference_update(other) – обновляет набор, сохраняя только элементы, найденные в любом наборе, но не в обоих.

Isdisjoint, Issubset, Issuperset
  • isdisjoint(other) – Возвращает True, если в наборе нет общих элементов с другими. Множества непересекающиеся тогда и только тогда, когда их пересечение является пустым множеством.
  • issubset() – проверяет, находится ли каждый элемент в множестве в другом.
  • issuperset() – Проверяет, все ли элементы другого элемента входят в набор.

Метод Копировать()

Вы можете создать идентичную копию существующего объекта набора, используя метод copy(). Этот метод также доступен для других типов структур данных, таких как список, словарь и т. д.

Удалите заданный объект из пространства имен с помощью встроенного ключевого слова del.

Холодное сердце
  • Замороженный набор является неизменяемым типом. После создания вы не сможете добавлять, удалять или обновлять элементы из списка.
  • Замороженный набор, будучи неизменяемым, хэшируется, может использоваться как «ключ» для словарей или элементов для другого объекта набора.
  • Замороженное множество создается с помощью функции “frozenset()”.
  • Замороженный набор предоставляет тот же набор методов по сравнению с «набором», например объединение(), пересечение, копирование(), isdisjoint() и т. д.

Краткое содержание

В этой статье вы увидели, что такое набор, разницу между набором и замороженным набором, как создавать и получать доступ к элементам набора, методам набора и т. д.

Все права защищены. © Linux-Console.net • 2019-2024

Исчерпывающее руководство по множествам в Python

Класс set (множество) — это одна из ключевых структур данных в Python. Она представляет собой неупорядоченную коллекцию уникальных элементов. Класс set , в некоторой степени, соответствует математическому множеству. Многие широко используемые математические операции, применимые к множествам, существуют и в Python. Часто вычисления, производимые над множествами, оказываются гораздо быстрее, чем альтернативные операции со списками. В результате, для того чтобы писать эффективный код, Python-программисту просто необходимо уметь пользоваться множествами. В этой статье я расскажу об особенностях работы с классом set в Python.

Инициализация множеств

Существует два способа создания объекта set : с использованием конструкции set(iterable) и путём помещения элементов, разделённых запятыми, в фигурные скобки — < . >. Если же при инициализации множества попытаться воспользоваться пустыми фигурными скобками — <> — тогда будет создан словарь, а не пустое множество. Для создания пустых множеств используется команда set() . Обратите внимание на то, что при инициализации множеств порядок элементов неважен, и на то, что дублирующиеся элементы в множество добавить не получится.

a = < "a", "b", "c", "d", "e", "f", "f" ># конструктору set можно передать любой итерируемый объект b = set(["a", "b", "c", "d", "e", "f"]) c = set(("a", "b", "c", "d", "e", "e", "f", "f")) # порядок элементов неважен d = set(["d", "e", "f", "a", "b", "c"]) # деструктурирование списка e = < *["a", "b", "c", "d", "e", "f"] >assert a == b == c == d == e # в одном множестве могут храниться значения разных типов f = set(["a", True, 123]) g = < "a", True, 123, True, 123 >assert f == g # set() - это множество, а <> - это словарь assert set() != <>

Какие элементы можно включить в состав множества? Это могут быть только элементы иммутабельных типов. Сюда входят такие типы, как float , int , string , bool и прочие подобные. А вот мутабельные типы — списки, словари, да и сами множества, в состав множеств включать нельзя. Если вас интересуют подробности о типах данных в Python — рекомендую почитать эту статью. Учитывая вышесказанное — следующая конструкция вызовет ошибку:

 < ["a", "b", "c"], True ># => TypeError: unhashable type: 'list'

Но что если случается так, что в множествах надо хранить некие уникальные последовательности значений? Подробнее об этом мы поговорим в конце статьи.

Примечание об иммутабельности

Иммутабельность — это ограничение, касающееся лишь встроенных типов. На практике, чтобы объект можно было добавить в множество, или чтобы его можно было использовать в качестве ключа в словаре, этот объект всего лишь должен быть хешируемым. По умолчанию объекты пользовательских классов обладают хешем, основанным на их идентификаторах. Равенство объектов определяется по их идентификаторам. Это значит, что два объекта, идентичные в плане атрибутов, будут равны друг другу только тогда, когда они представляют один и тот же объект, или в том случае, если для них определён пользовательский оператор eq .

Если для некоего класса определён пользовательский оператор eq , то объекты этого класса перестают быть хешируемыми, если только для них не будет определён пользовательский оператор hash . Тут важно то, что если два объекта равны, то их хеши тоже должны быть равны. В противном случае при добавлении подобных объектов в словарь или в множество возникнут проблемы. Дело в том, что при проверке наличия значения в составе ключей словаря или в составе множества, проверяются и хеши и равенство объектов.

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

Добавление элементов в множества

Существует множество способов добавления элементов в множество. Для того чтобы осуществить изменение (мутацию) множества, отдельный элемент в него можно добавить командой .add() . Итерируемый объект добавляют командой .update() , или, что то же самое, используя оператор |= :

a = set() # добавление строкового элемента a.add("hello") # Следующий код НЕ эквивалентен предыдущему. # Метод update ожидает поступления итерируемого объекта, поэтому # строка рассматривается как итерируемый объект, содержащий символы # которые и добавляются в множество a.update("hello") assert a == < 'hello', 'h', 'e', 'l', 'o' ># А тут в множество добавляются две строки, так как они размещены в списке a.update(["hi", "world"]) assert a ==

Под «мутацией» я понимаю изменение исходного объекта. Есть ещё команды, которые не изменяют исходное множество. Например — метод . union() , или его эквивалент — оператор | :

a = < "a", "b" , "c" >b = < "a", "c", "d" >assert a | b == a.union(b) == < "a", "b", "c", "d" ># исходные объекты не изменились assert a == < "a", "b" , "c" >and b ==

Явное различие поведения методов .update() и .union() можно продемонстрировать, разобрав следующий пример:

def add_to_set1(a, b): a.update(b) return a def add_to_set2(a, b): a = a.union(b) return a a = < "a", "b" , "c" >b = < "a", "c", "d" ># Исходный объект был модифицирован # и будет равен возвращённому объекту assert a == add_to_set1(a, b) a = < "a", "b" , "c" >b = < "a", "c", "d" ># Исходный объект НЕ был модифицирован # и не будет равен возвращённому объекту assert a != add_to_set2(a, b)

И наконец — два множества можно конкатенировать, использовав деструктурирование:

a = < "a", "b" , "c" >b = < "a", "c", "d" >assert < *a, *b >==

Этот приём будет работать аналогично методу .union() , но я рекомендую пользоваться именно .union() .

Обратите внимание на то, что в предыдущих примерах я пользовался методом .update() , но в них можно было бы применить и оператор |= . Это значит, что a |= b ( .update() ) — это НЕ то же самое, что a = a | b (.union()) . Дело в том, что в первом фрагменте кода осуществляется изменение объекта, хранящегося в a , а во втором примере a назначается новое значение.

Удаление элементов множеств

Мы рассмотрели команды для добавления элементов в множества. Существуют похожие на них команды, применяемые при удалении элементов. Вот как эти команды можно соотнести с уже известными вам командами:

  • Аналог .add() — .remove() .
  • Аналог .update() — .difference_update() или -= .
  • Аналог .union() — .difference() или — .
a = < "a", "b" , "c" >a.remove("b") assert a == < "a", "c" >a = < "a", "b" , "c" ># Так же, как .update(), эта команда ожидает итерируемый объект # В результате здесь удаляются "a" и "b", # а не целая строка "ab" a.difference_update("ab") assert a == < "c" >a = < "a", "b" , "c" >a.difference_update(["ab"]) # "ab" нет в составе элементов множества, поэтому ничего не удаляется assert a == < "a", "b", "c" ># Оператор -, эквивалент метода .difference(), # не модифицирует исходный объект a = < "a", "b" , "c" >b = a - < "b", "c" >assert a != b and b ==

Снова хочу обратить ваше внимание на то, что надо помнить о разнице между конструкциями вида a -= b (исходное множество изменяется) и a = a — b (исходное множество не изменяется).

Имеется и ещё несколько методов, которые могут пригодиться для удаления объектов:

  • .clear() — очищает множество.
  • .remove() — удаляет элемент лишь в том случае, если он существует (в противном случае выдаёт ошибку); .discard() — работает похожим образом, но, если элемента не существует, ошибку не возвращает.
  • .pop() — удалит случайный элемент из множества и вернёт этот элемент.

Другие операции для работы с множествами

Одна из сильных сторон Python-множеств заключается в наличии большого количества стандартных операций, предназначенных для работы с ними. Мы обсудили команды для модификации множеств путём добавления и удаления элементов, но это — далеко не всё, что можно делать с множествами.

Пересечение множеств

Пересечением двух множеств является множество элементов, входящих в состав обоих множеств. Для выполнения этой операции используются следующие методы и операторы:

  • Команды, при выполнении которых множество не меняется: .intersection() или & . Например — a.intersection(b) или a & b .
  • Команды, при выполнении которых множество меняется: .intersection_update() или &= .
a = < "a", "b", "c" >b = < "b", "c", "d" >assert a & b ==
Симметрическая разность множеств или дизъюнктивное объединение

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

  • Команды, при выполнении которых множество не меняется: . symmetric_difference() или ^ . Например — a.symmmetric_difference(b) или a ^ b .
  • Команды, при выполнении которых множество меняется: .symmetric_difference_update() или ^= .
a = < "a", "b", "c" >b = < "b", "c", "d" >assert a ^ b ==

Методы проверки наличия элементов в множествах, сравнение множеств

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

Проверка принадлежности элемента множеству

Вероятно, это — та операция, к которой вы будете прибегать чаще, чем к другим. Проверка наличия элемента в множестве выполняется с помощью оператора in . А проверка отсутствия элемента — с помощью оператора not in . Для таких операций над множествами, в отличие от подобных проверок, выполняемых в применении к спискам, характерна константная временная сложность — O(1). В результате, по мере роста размеров множества, не будет страдать скорость проверки наличия или отсутствия в нём неких элементов.

a = < "a", "b", "c" >assert "a" in a assert "d" not in a
Проверка того, является ли одно множество подмножеством другого

Множество является подмножеством другого множества в том случае, если все элементы первого множества входят в состав второго. Например, (A, B, C) — это подмножество (A, B, C, D) . В Python подобную проверку можно провести, воспользовавшись методом .issubset() или оператором = и > .

a = < "a", "b", "c" >b = < "a", "b" >assert a.issubset(b) == (a = b and a > b
Проверка того, что в двух множествах нет общих элементов

Если в множествах нет общих элементов, их называют непересекающимися множествами. В Python соответствующая проверка выполняется с помощью метода .isdisjoint() .

a = < "a", "b", "c" >b = < "a", "b" >c = < "d" ># без isdisjoint() assert len(a & c) == 0 and len(a & b) != 0 # с этим методом assert a.isdisjoint(c) and not a.isdisjoint(b)

Абстракция множеств

Так же, как и в случае со списками и словарями, при работе с множествами можно воспользоваться так называемой абстракцией множеств (set comprehension). Делается это путём добавления обрабатываемого выражения в фигурные скобки и через возврат единственного мутабельного элемента на каждом проходе цикла: < for . in . > .

# преобразование списка в множество с добавлением 1 к каждому элементу assert < i+1 for i in [1, 2, 3, 4] >== < 2, 3, 4, 5 ># только чётные числа a = < i for i in range(10) if i % 2 == 0 >a.update(< -3, 100 >) # Преобразование множества в список с добавлением 1 к каждому элементу # ВНИМАНИЕ: перебирая множество, не рассчитывайте на то, что сохранится тот # порядок следования элементов, в котором они были в него добавлены print([i+1 for i in a]) # => [1, 3, 5, 101, 7, 9, -2]

Хранение в множествах данных более сложных типов

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

A -> B -> D D -> C -> E -> B

Потом надо быстро проверить, прошлись ли мы по определённому пути. Нужно, чтобы такая проверка проводилась бы быстро, поэтому совершенно естественным будет использовать для её реализации множество. Как это сделать, если список, из-за его мутабельности, нельзя добавить в множество? К нашему счастью, в подобных обстоятельствах можно воспользоваться кортежем, классом tuple , который, по сути, представляет собой иммутабельную версию списка. Рассмотрим пример.

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

# можно перейти от ключа к значениям graph =

Визуализировав это описание, я получил такой граф.

Граф

Если вы задаётесь вопросом о том, как я создал такой граф — знайте, что сделал я это, прибегнув к graphviz и написав следующий код:

from graphviz import Digraph dot = Digraph() for k in graph.keys(): dot.node(k, k) edges = [] for k, v in graph.items(): edges += [f"" for to in v] dot.edges(edges) dot.render(view=True)

Теперь я займусь случайным блужданием по графу, проходя от 1 до 10 узлов, после чего сохраню результирующие пути в объекте set в виде кортежей. Посмотрим, сколько уникальных путей мы сможем сгенерировать за 100 проходов по графу:

import random def perform_random_walk(graph, n_steps): node = random.sample(list(graph), 1)[0] path = [node] for _ in range(n_steps): node = random.sample(graph[node], 1)[0] path.append(node) return tuple(path) paths = set() lengths = list(range(1, 10+1)) for _ in range(100): paths.add(perform_random_walk(graph, random.choice(lengths))) len(paths) # => 83

Из 100 случайных проходов по графу 83 оказались уникальными.

А что если нас не волнует порядок узлов, а нужно лишь сохранить сведения о посещённых узлах? Тогда будет смысл хранить отдельные пути в множествах, но, как уже было сказано, множества мутабельны, помещать их в другие множества нельзя. В такой ситуации, вместо обычных множеств, описываемых классом set , можно прибегнуть к неизменяемым множествам, представленным классом frozenset . Чтобы это сделать — поработаем с кодом цикла из предыдущего примера:

paths = set() lengths = list(range(1, 10+1)) for _ in range(100): path = perform_random_walk(graph, random.choice(lengths)) paths.add(frozenset(path)) len(paths) # => 21

Итоги

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

О, а приходите к нам работать? �� ��

Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.

Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь.

Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *