Множества и словари
Внимание: подробный рассказ про хеш-функции и хеш-таблицы см. в записях предыдущих лет.
Множества и hash()
id() — уникальность объекта, ничего не знает про равенство
- сравнение двух объектов может быть тяжёлой операцией
hash() — числовой хеш от константного объекта
- создаётся вместе с объектом
- для изменяемого объекта (например, списка) смысла не имеет
- если хеши не равны, объекты тоже не равны
- обратное, в целом, неверно
- создаётся вместе с объектом
Множества
Задаются перечислением или сборкой в { }
Поддерживают теоретико-множественные операции "| & ^ -"
Множества в Python реализованы как хеш-таблицы:
- размер таблицы приблизительно пропорционален количеству элементов (изменение размера как в списках)
- повторное хеширование при коллизии
константный поиск в среднем (+линейное масштабирование)
Элементы множества неупорядочены (в действительности, почти упорядочены по хешам, с учётом перехеширования и масштабирования):
Словари
Задача: хранить произвольные объекты, каждый из которых взаимно однозначно соответствует хорошо хешируемой константе.
(до Python3.6 — множество ключей + ссылка на хранимый объект)
(современный Python) хеш-список (без дыр) + журнал индесксов
Операция добавления легче операции удаления (кому нужно удалять из словаря?)
Сохраняет порядок добавления элементов
Использование
dict — как массив с константными элементами вместо индекса
- Задание и обращение к элементу
- Циклический конструктор
- Работа со словарём
keys(), values(), items()
- цикл по словарю
[] vs .get() vs .setdefault()
.update() и прочие методы
Относительно новое — | и |=
Словари внутри Python
globals()/locals()
1 >>> QQ 2 Traceback (most recent call last): 3 File "<stdin>", line 1, in <module> 4 NameError: name 'QQ' is not defined 5 >>> globals() 6 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f434c1b4190>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__cached__': None, 'rlcompleter': <module 'rlcompleter' from '/usr/lib64/python3.7/rlcompleter.py'>} 7 >>> globals()["QQ"]=100500 8 >>> QQ 9 100500 10 >>> globals() 11 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f434c1b4190>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__cached__': None, 'rlcompleter': <module 'rlcompleter' from '/usr/lib64/python3.7/rlcompleter.py'>, 'QQ': 100500}
Передача пространства имён как параметра
eval() — интерпретация и вычисление выражения
exec() — интерпретация и выполнение куска кода
И туда, и туда можно передать словарь для того, что это выражение/код увидит в качестве globals() и locals()
TODO Пример?
Именные параметры функции
Позиционные параметры — кортеж, именные — словарь.
Ещё немного занудства про параметры функций: значения по умолчанию ≠ именные параметры
Модуль collections
Мелкий изврат: def tree(): return defaultdict(tree) (тут)
- …
Д/З
- Прочитать и прощёлкать
про множества в учебнике и в документации
про словари в учебнике и в документации
- (это задача не на словари ☺)
EJudge: RandSquare 'Точка в квадрате'
Написать функцию randsquare(A, B), принимающую на вход две пары вещественных чисел — координаты диагонали квадрата на плоскости. Функция должна возвращать случайную точку, принадлежащую этому квадрату (ожидаются точки из любого места квадрата, например, с его границы, хотя вероятность этого события будем считать нулевой). «Случайность» в тестах определяется как достаточно равномерное распределение точек по всей поверхности квадрата.
# Это ошибочный тест! for i in range(100000): x, y = randsquare((0,-10.01), (0,10.01)) if x**2+y**2 > 100: print(f"Error: {x}:{y}")
Error: -0.002220480791093505:-10.002541596486285 Error: 0.0008220827409817354:-10.005657011321619 Error: -0.0019093494480841855:10.007641260813324
1 def showgr(Dots, Corners, Name="Dots"): 2 import numpy as np 3 import matplotlib.pyplot as plt 4 5 X, Y = zip(*Dots) 6 fig, ax = plt.subplots(num=Name) 7 ax.set_aspect(1) 8 ax.scatter(X, Y) 9 ax.fill(*Corners, fill=False) 10 plt.show() 11 12 def show(A, B, num=1000): 13 dots = [randsquare(A, B) for i in range(num)] 14 R = [ (A[0], (B[0]+A[0])/2-(B[1]-A[1])/2, B[0], (B[0]+A[0])/2+(B[1]-A[1])/2), 15 (A[1], (B[1]+A[1])/2+(B[0]-A[0])/2, B[1], (B[1]+A[1])/2-(B[0]-A[0])/2)] 16 showgr(dots, R) 17 18 show((6,7), (2,12), 5000)
EJudge: PublicFriend 'Знаком со всеми'
Вводятся в столбик пары неотрицательных целых чисел через запятую. Каждая пара M, N обозначает взаимное знакомство людей под номерами M и N. Ввод заканчивается парой 0, 0 (не учитывается, и вообще человек N считается незнакомым с человеком N ). Вывести через пробел в порядке возрастания номера тех, кто знаком со всеми остальными, или пустую строку, если таких нет.
7, 9 1, 7 9, 2 9, 2 9, 7 2, 9 9, 2 2, 9 7, 1 9, 2 9, 2 2, 1 7, 2 7, 9 7, 1 7, 1 0, 0
2 7
EJudge: PokeMon 'Покемоны'
Участники некоторой карточной игры владеют несколькими колодами, из которых они составляют свой уникальный игровой набор. Каждая колода имеет номер; колоды с одинаковыми номерами содержат совпадающие наборы карт. Ввести строки вида "имя игрока / номер колоды" (колода принадлежит игроку) или "номер колоды / название карты" (карта входит в колоду); последняя строка пустая. Вывести в алфавитном порядке имя каждого игрока, который может составить игровой набор из наибольшего числа различных карт.
0 / Misdreavus Svjatoslav Devjatkov / 3 2 / Yamask Vsevid Mladenov / 1 1 / Keldeo 0 / Keldeo 1 / Misdreavus 2 / Scatterbug 0 / Crawdaunt 2 / Keldeo 1 / Vanillite Svjatoslav Devjatkov / 0 2 / Gardevoir Neljub Mstislavin / 2 2 / Crawdaunt 0 / Yamask 3 / Reshiram
Neljub Mstislavin Svjatoslav Devjatkov
EJudge: LevKarenina 'Лев Каренина'
В первой строке ввода находится четыре символа: знак препинания в конце предыдущего предложения p, первая буква слова в начале предложения b, первая буква последнего слова в предложении g и знак препинания в конце предложения e. Все остальные строки, кроме последней, непустые, и содержат строки некоторого текста. Текст состоит из слов (последовательностей любых непробельных символов) и разделителей (последовательностей пробельных символов). Считается, что «предложение» — это то, что заканчивается на p или e. Вывести в предлагаемой форме
- самое популярное слово
начинающееся на b,
& в начале предложений,
& перед которыми стояло p
- и самое популярное слово
начинающееся на g,
& в конце предложений,
& заканчивающихся на e
- а также количество вхождений таких критериев.
Если какой-то из этих критериев нельзя удовлетворить, вывести «...» и 0. Если критерию удовлетворяет несколько слов, вывести то, что встретилось в заданном контексте раньше.
.Sf! Syringes expanses syringes syringes fordo! Fenceless fills syringes fills fills syringes. Salves sis fordo sis salves fordo fenceless salves expanses? Fills syringes. Syringes syringes salves sis salves salves fills! Expanses fordo fenceless. Salves expanses expanses salves fills! Sis sis fills fills! Syringes sis syringes syringes expanses. Fills fenceless fordo syringes salves! Fenceless fordo fenceless syringes sis expanses salves fordo. Syringes sis salves syringes syringes salves expanses! Expanses fordo expanses salves expanses fills syringes fills syringes salves fenceless. Fenceless fills salves? Fenceless sis expanses syringes expanses fenceless fenceless sis fenceless syringes sis expanses! Fenceless syringes syringes sis. Sis fate!
Salves 2 - fills! 3
- самое популярное слово