Тип Set: множества
Множество (set) в Python — это изменяемая неупорядоченная коллекции неизменяемых и уникальных объектов.
- Можно добавлять элементы в множество и удалять их:
set
— изменяемая коллекция.Если насыпать горсть пшеницы в плошку — можно высыпать часть зёрен, а можно добавить сколько угодно (в отличие от плошки, элементы в set не посыпятся через край). - Множество — неупорядоченная коллекция, к элементам нельзя обратиться по индексам или автоматически вывести их по порядку.Какое из зёрен в плошке будет первым, а какое — последним? Да никакое! Обратиться к зёрнам по индексам не получится.
- Изменить отдельный элемент в множестве нельзя: элементами множества могут быть только неизменяемые объекты (числа, строки, кортежи и прочие хешируемые объекты).Тут метафора с зёрнами даёт сбой, придётся обойтись без неё.
- Элементы множества должны быть уникальны. Добавить в множество элемент со значением, которое уже есть в этом множестве, не получится; однако и ошибки это не вызовет.Нет двух одинаковых зёрен; каждое из них уникально.Неупорядоченные коллекции хранят элементы так, что невозможно определить, какой элемент первый, какой последний, а какой, к примеру, восьмой. Даже при выводе в цикле неупорядоченная коллекция будет возвращать свои элементы в разном порядке.
Литерал для множеств — фигурные скобки.
Запустите
код несколько раз: как и положено детским игрушкам, из ящика они
вываливаются беспорядочной грудой, каждый раз по-разному.
КодPYTHON
5
1
# Литерально set объявляется с помощью фигурных скобок.
2
toys = {'куклы', 'кубики', 'странная штука', 'самолетики', 'мелки'}
3
4
for toy in toys:
5
print(toy)
Множества — это коллекции: они содержат набор элементов. Однако множества — это не последовательности: элементы множества нельзя перебрать «по очереди», порядок будет всегда разный; а последовательностями называют упорядоченные коллекции.
Из особенностей множеств можно выделить:
- удобство исключения дубликатов, например, при добавлении элементов к множеству;
- возможность выполнения математических операций над множествами — вычисление пересечения и разности множеств.
Создание объекта set
Как и другие коллекции, создать множество можно через литералы или через встроенную функцию.
Скопировать кодPYTHON# Литеральное объявление множества
movie_ratings_set = {5.0, 4.1, 4.3, 4.7, 4.7, 3.8}
print(movie_ratings_set)
# Вывод в консоль: {5.0, 4.3, 3.8, 4.1, 4.7}
# Порядок элементов не соответствует литералу.
print(type(movie_ratings_set))
# Вывод в консоль: <class 'set'>
movie_ratings = [5.0, 4.1, 4.3, 4.7, 4.7, 3.8]
# Объявление множества через функцию set()
movie_ratings_set = set(movie_ratings)
print(movie_ratings_set)
# Вывод в консоль: {5.0, 4.3, 3.8, 4.1, 4.7}
# Элементов получилось меньше, чем в исходном списке: неуникальные значения удалены.
# Порядок элементов не соответствует исходному списку.
print(type(movie_ratings_set))
# Вывод в консоль: <class 'set'>
Создать пустое множество можно только через функцию
set()
; объявить пустое множество литерально не получится: будет создан пустой словарь, а не пустое множество.Скопировать кодPYTHONempty_set = set()
print(empty_set)
# Вывод в терминал: set()
print(type(empty_set))
# Вывод в терминал: <class 'set'>
empty_set = {}
print(type(empty_set))
# Вывод в терминал: <class 'dict'>
Уникальность элементов множества
Все элементы множества уникальны; при добавлении неуникальных элементов они не будут включены в множество.
Попрактикуемся
на списке фильмов из онлайн кинотеатра: иногда в нём попадаются
повторяющиеся элементы. Чтобы при дальнейшей обработке данных о фильмах
дублирование не привели к ошибке, можно исключить их, преобразовав
список в множество.
Скопировать кодPYTHONmovies = ['Матрица', 'Сеть', 'Хакеры', 'Трон', 'Тихушники', 'Сеть', 'Трон']
uniq_movies = set(movies)
print(uniq_movies)
# Вывод в терминал: {'Сеть', 'Матрица', 'Тихушники', 'Хакеры', 'Трон'}
# Дублирующиеся названия удалены!
Найдите количество уникальных символов в строке, без учёта пробелов.
КодPYTHON
5
1
not_uniq_str = 'съешь же ещё этих мягких французских булок да выпей чаю'
2
3
count_char = len(set(not_uniq_str.replace(' ', '')))
4
5
print(count_char)
Элемент множества — хешируемый объект
Элементом множества не могут быть данные изменяемых типов, например — списки.
Скопировать кодPYTHON# Литерально объявим set, элементами которого будут списки
movies = ['Матрица', 'Сеть', 'Хакеры', 'Трон',]
movie_ratings = [4.7, 5.0, 4.3, 3.8]
movies_set = {movies, movie_ratings}
print(movies)
# Вывод в терминал: TypeError: unhashable type: 'list'
# Ничего не вышло: элементами множества могут быть только хешируемые объекты.
Функция
set()
создаст множество из списка или словаря.- Множество, созданное из словаря, будет содержать только ключи исходного словаря. Ключи словаря — всегда неизменяемые объекты, потому проблем не возникнет.
- Из списка множество будет создано лишь в том случае, если элементы списка — неизменяемые объекты.
Скопировать кодPYTHON# Создаём словарь: коллекцию, каждый элемент которой состоит из пары "ключ:значение"
# Ключами словаря могут быть только хешируемые объекты.
# Каждый ключ в словаре - уникален
movie_info = {'Матрица': 4.5, 'Трон': 4.8}
# В set() передан словарь
movie_names = set(movie_info)
print(movie_names)
# Вывод в терминал: {'Трон', 'Матрица'}
# В результате получилось множество,
# состоящее из ключей исходного словаря
# В set() передан список элементов типа float
movie_ratings = [5.0, 4.1, 4.3, 4.7, 4.7, 3.8]
movie_ratings_set = set(movie_ratings)
# Множество успешно создано
print(movie_ratings_set)
# Вывод в терминал: {5.0, 4.3, 3.8, 4.1, 4.7}
# Один из элементов исходного списка - список (нехешируемый объект)
movie_ratings = [5.0, 4.1, [4.3, 4.7], 4.7, 3.8]
# При преобразовании исходного списка в множество
# программа выдаст ошибку:
movie_ratings_set = set(movie_ratings)
print(movie_ratings_set)
# Вывод в терминал: TypeError: unhashable type: 'list'
Работа с множествами
Рассмотрим работу с множествами на примере игрушек Максима и Леры:
Скопировать кодPYTHONmaxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
lera_toys = {'скакалка', 'кукла', 'кубики', 'юла'}
Принадлежность объекта множеству
Чтобы определить, есть ли нужный элемент в множестве, применяют оператор
in
.
Он работает так же, как и для последовательностей, но поиск выполняется
гораздо быстрее, чем в списках — это связано с особенностью хранения
множеств в памяти.Проведём поиск в списке и в множестве; в каждой коллекции создадим по миллиону элементов.
Чтобы засечь время выполнения операции, импортируем в код встроенный модуль
time
.КодPYTHON
24
1
import time
2
# Создается множество
3
num_set = set()
4
# С помощью цикла множество заполняется элементами от 0 до 999999
5
for num in range(10**6):
6
num_set.add(num)
7
8
# В start_time сохраняем время в секундах перед началом поиска
9
start_time = time.time()
10
if 954365 in num_set:
11
print(True)
12
13
# Выводим в терминал время, затраченное на поиск нужного элемента:
14
print((time.time() - start_time))
15
16
# Создаём и наполняем список:
17
num_list = []
18
for num in range(10**6):
19
num_list.append(num)
20
21
start_time = time.time()
22
if 954365 in num_list:
23
print(True)
24
print((time.time() - start_time))
Поиск по списку выполняется быстро, но поиск в множестве — заметно быстрее.
Поиск
по хешируемым объектам происходит почти мгновенно. Преобразование из
списка в множество может занимать много времени, но если требуется
выполнить поиск по коллекции больше двух раз — будет выгоднее потратить
время на преобразование и затем искать по множеству.
Добавление элемента
Для добавления элемента в множество применяют метод
add()
. Он очень похож на метод списков append()
; если добавляемый элемент уже есть в множестве — ничего не произойдёт, множество не изменится.Скопировать кодPYTHONmaxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
print(id(maxim_toys))
# Вывод в терминал: 33482552
maxim_toys.add('самолётик')
# Проверим что элемент добавлен к исходному множеству
print(id(maxim_toys))
# Вывод в терминал: 33482552
print(maxim_toys)
# Вывод в терминал:{'скакалка', 'машинка', 'самолетик', 'пистолетик', 'кубики'}
# Попробуем добавить ещё кубики в множество:
maxim_toys.add('кубики')
print(maxim_toys)
# Вывод в терминал:{'скакалка', 'машинка', 'самолетик', 'пистолетик', 'кубики'}
# Новый элемент в множестве не появился.
Удаление элемента множества
Для удаления элемента есть три метода:
remove()
, discard()
и pop()
.Методы
remove()
и discard()
очень схожи: они удаляют элемент из множества. При попытке удалить несуществующий элемент методом remove()
программа завершится с ошибкой.Скопировать кодPYTHONmaxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
# Удаление существующего элемента
maxim_toys.remove('кубики')
print(maxim_toys)
# Вывод в терминал: {'машинка', 'скакалка', 'пистолетик'}
maxim_toys.discard('машинка')
print(maxim_toys)
# Вывод в терминал: {'скакалка', 'пистолетик'}
# Удаление несуществующих элемента
maxim_toys.discard('кукла')
print(maxim_toys)
# Вывод в терминал: {'скакалка', 'пистолетик'}
maxim_toys.remove('кукла')
print(maxim_toys)
# Вывод в терминал: KeyError: 'кукла'
Метод
pop()
удаляет и возвращает случайный элемент множества. Для жеребьевки отличный вариант, результат предугадать нельзя.КодPYTHON
4
1
maxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
2
toy = maxim_toys.pop()
3
print(f'Вам — {toy}!')
4
print(f'Оставшиеся игрушки: {maxim_toys}')
Очистка множества
Для очистки существующего множества есть метод
сlear()
:Скопировать кодPYTHONmaxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
maxim_toys.clear()
print(maxim_toys)
# Вывод в терминал: set()
Операции над множествами
Ключевое отличие множеств от других коллекций — возможность выполнять над множествами математические операции.
Пересечение
Поиск
«пересечения» (поиск совпадающих элементов) двух коллекций —
востребованная операция в программировании: например, пересечением можно
найти одинаковые почтовые адреса в двух базах данных или одинаковые
товары в интернет-магазинах. Можно сравнить коллекции в цикле, определяя
наличие элемента через
in
, но это ресурсоёмко и долго. Для поиска пересечения двух множеств есть оператор
&
(логическое И
), он возвращает новое множество, в котором будут собраны элементы, одновременно присутствующие в обоих исходных множествах:Скопировать кодPYTHONmaxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
lera_toys = {'скакалка', 'кукла', 'кубики', 'юла'}
# Создаём множество, элементы которого есть в первом И (&) во втором множестве:
overlap = maxim_toys & lera_toys
print(overlap)
# Вывод в терминал: {'кубики', 'скакалка'}
Получить пересечение множеств можно и другим способом: для этого есть метод
intersection()
:Скопировать кодPYTHONmaxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
lera_toys = {'скакалка', 'кукла', 'кубики', 'юла'}
overlap = maxim_toys.intersection(lera_toys)
print(overlap)
# Вывод в терминал: {'кубики', 'скакалка'}
С
помощью этого метода можно получить пересечение множества с любым
итерируемым объектом, все элементы которого — хешируемые объекты
(например — со списком, элементы которого — числа или строки).
Это
справедливо и для других методов множеств: в аргументы этих методов
можно передать любой итерируемый объект с хешируемыми элементами.
Объединение
В результате объединения двух множеств (операция «логическое
ИЛИ
») будет создано новое множество, содержащее все элементы исходных. Логическое ИЛИ обозначается операндом |
.Скопировать кодPYTHONmaxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
lera_toys = {'скакалка', 'кукла', 'кубики', 'юла'}
# Создаём множество, элементы которого есть в первом ИЛИ (|) во втором множестве:
unite = maxim_toys | lera_toys
print(unite)
# Вывод в терминал: {'кубики', 'кукла', 'скакалка', 'юла', 'машинка', 'пистолетик'}
Другой способ объединить два множества — применить метод
union()
.Скопировать кодPYTHONmaxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
lera_toys = {'скакалка', 'кукла', 'кубики', 'юла'}
unite = maxim_toys.union(lera_toys)
print(unite)
# Вывод в терминал: {'кубики', 'кукла', 'скакалка', 'юла', 'машинка', 'пистолетик'}
Разность
Разность
множеств возвращает новое множество, в которое войдут элементы первого
множества, не пересекающиеся с элементами второго. Оператор для поиска
разности — обычный минус
-
.Скопировать кодPYTHONmaxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
lera_toys = {'скакалка', 'кукла', 'кубики', 'юла'}
# Создаём множество, элементы которого есть в первом множестве и отсутствуют во втором:
diff = maxim_toys - lera_toys
print(diff)
# Вывод в терминал: {'машинка', 'пистолетик'}
Разность можно найти и методом
difference()
:Скопировать кодPYTHONmaxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
lera_toys = {'скакалка', 'кукла', 'кубики', 'юла'}
diff = maxim_toys.difference(lera_toys)
print(diff)
# Вывод в терминал: {'машинка', 'пистолетик'}
Симметрическая разность
Симметрической
разностью двух множеств будет третье множество, каждый элемент которого
принадлежит либо первому, либо втором множеству, но не их пересечению.
Для поиска симметрической разности применяют символ «карет»
^
:Скопировать кодPYTHONmaxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
lera_toys = {'скакалка', 'кукла', 'кубики', 'юла'}
sym_diff = maxim_toys ^ lera_toys
print(sym_diff)
# Вывод в терминал: {'машинка', 'пистолетик', 'юла', 'кукла'}
Симметрическую разность можно найти и с помощью метода
symmetric_difference()
Скопировать кодPYTHONmaxim_toys = {'машинка', 'скакалка', 'кубики', 'пистолетик'}
lera_toys = {'скакалка', 'кукла', 'кубики', 'юла'}
# Создаём множество, состоящее из элементов обоих множеств,
# с исключением пересекающихся:
sym_diff = maxim_toys.symmetric_difference(lera_toys)
print(sym_diff)
# Вывод в терминал: {'машинка', 'пистолетик', 'юла', 'кукла'}
Методов работы с множествами больше, полный список можно найти в официальной документации.
Вычислите и напечатайте количество одинаковых элементов в коллекциях
num_string_1
и num_string_2
.КодPYTHON
7
1
num_string_1 = '100 13 2 143 12 3 55 4 64 18 56'
2
num_string_2 = '234 2 56 432 3 100 12 99 43 18 31 64'
3
4
set_num_string_1 = set(num_string_1.split(' '))
5
set_num_string_2 = set(num_string_2.split(' '))
6
7
print(len(set_num_string_1.intersection(set_num_string_2)))
Антон
получил в ответ от сервера перечень id клиентов в виде строки, где id
разделены пробелами. Его задача — удалить дубликаты и отсортировать
список id по возрастанию.
Напишите
программу, которая поможет Антону формировать такие списки. Если в
списке будет найден дублирующийся id — программа должна вывести в
терминал сообщение «Найден дубликат id
<значение_id>
».КодPYTHON
13
1
# Напишите программу и обработайте этот перечень id
2
id_string = '32 48 2 6 14 58 2 88 9 14 123 48 3 17 42 42 7'
3
4
list_id_string = [int(id) for id in id_string.split(' ')]
5
new_set = set()
6
for id in list_id_string:
7
if id in new_set:
8
print(f'Найден дубликат id {id}')
9
new_set.add(int(id))
10
11
12
13
print(sorted(new_set))