Модуль 4 · Урок 4.4
Словари и подсчёт частот
Доступ по смысловому ключу, обход пар и частотная таблица.
В списке значение ищут по номеру позиции. Но часто нужен ответ на другой вопрос: какой балл у Анны, сколько раз встретилась буква A. Словарь находит значение по смысловому ключу — имени, слову, букве — и поэтому естественно хранит частоты. Частотная таблица — это много счётчиков из урока о while сразу, по одному на каждое значение.
Работать будем с баллами учеников {"Анна": 91, "Илья": 84} и словом "BANANA", в котором посчитаем буквы.
Словарь
Словарь хранит пары «ключ — значение» и ищет значение по ключу. В списке элемент ищут по позиции. Иногда нужен доступ по имени: «балл Анны», «количество буквы A». Словарь (dict) хранит соответствия между ключами и значениями.
scores = {"Анна": 91, "Илья": 84}print(scores["Анна"])scores["Марк"] = 88scores["Анна"] = 95print(scores)Ключ уникален: новое присваивание тому же ключу заменяет его значение. Значения могут повторяться. Чтение отсутствующего ключа через квадратные скобки вызывает ошибку:
scores = {"Анна": 91, "Илья": 84}print(scores["Ольга"])Безопасное чтение и проверка ключа:
scores = {"Анна": 91, "Илья": 84}print(scores.get("Ольга", 0))print("Анна" in scores)print(91 in scores)get(key, default) возвращает значение либо указанное значение по умолчанию; ключ от этого не добавляется. Без второго аргумента значение по умолчанию — None. Операция in для словаря проверяет ключи, а не значения: 91 есть среди значений, но ключом не является.
Какие бывают ключи
Ключом может быть число, строка или кортеж из них; список — нельзя. Ключ не должен меняться, пока лежит в словаре, поэтому изменяемые значения — список, словарь, множество — ключами быть не могут:
d = {[1, 2]: 3}Тонкости:хеш и хешируемые значения
Для быстрого поиска словарь вычисляет по ключу число — хеш — и по нему сразу находит место хранения, не перебирая все пары. Если бы ключ изменился, изменился бы и хеш, и пара потерялась бы. Значения, у которых есть хеш, называют хешируемыми: числа, строки, кортежи из таких значений. Кортеж, содержащий список, не годится: список внутри него может измениться.
Значения словаря такими ограничениями не связаны: можно хранить под именем пользователя целый список его результатов.
Обход словаря
Словарь обходят по ключам или по парам; порядок — порядок добавления.
scores = {"Анна": 91, "Илья": 84}for name in scores: print(name) total = 0for name, score in scores.items(): print(name, score) total += scoreprint(total).items() позволяет получать пары, .keys() — ключи, .values() — значения; list(scores) создаёт список ключей.
Ключи идут в порядке добавления. Это не сортировка: по алфавиту или величине они сами не выстраиваются, а замена значения не переносит ключ в конец. Не добавляй и не удаляй ключи во время обхода того же словаря.
Частотная таблица
Частотная таблица — словарь «значение → сколько раз встретилось». Частота — число появлений значения. Пройдём по буквам и увеличим соответствующий счётчик. Нажми «Запуск» и пройди подсчёт по шагам: на каждой итерации for берёт очередную букву, а следующая строка увеличивает её счётчик:
text = "BANANA"counts = {}for letter in text: counts[letter] = counts.get(letter, 0) + 1print(counts)Если буква встретилась впервые, get даёт 0. После прибавления записывается 1. При следующих появлениях читается накопленное значение: для первой A get даёт 0, и в словаре появляется 'A': 1, а для второй A — уже 1, и запись становится 'A': 2.
Самое частое значение
Самое частое значение находят вторым проходом по парам словаря. По списку ['a', 'b', 'a', 'c', 'b', 'a'] найдём значение с наибольшей частотой; при равенстве выберем то, которое впервые встретилось раньше:
items = ['a', 'b', 'a', 'c', 'b', 'a']counts = {}for item in items: counts[item] = counts.get(item, 0) + 1 best_item = Nonebest_count = 0for item, count in counts.items(): if count > best_count: best_item = item best_count = countprint(best_item, best_count)Строгое > оставляет прежнего победителя при равенстве. Порядок словаря совпадает с порядком первых появлений. Для пустого входа ответ остаётся None, 0 — это выбранное обозначение отсутствия результата.
Тонкости:равные ключи разных типов
Ключи 1, 1.0 и True сравниваются равными и используются как один ключ. Поэтому в смысловых идентификаторах лучше не смешивать числа и логические значения без необходимости.
Итог
Словарь отвечает на вопрос «что лежит под этим ключом», а частотная таблица считает все значения за один проход. Вот что понадобится дальше.
{"Анна": 91}Пары «ключ — значение»; ключ уникален, новое присваивание заменяет значение.- Чтение
d[key]без ключа —KeyError;d.get(key, 0)— значение или запасное. inПроверяет ключи, а не значения.- КлючиЧисло, строка, кортеж из них; список и другие изменяемые значения — нельзя.
- Обход
for key in d— ключи;for key, value in d.items()— пары; порядок — порядок добавления. - Частоты
counts[x] = counts.get(x, 0) + 1для каждого значения. - Самое частоеВторой проход по парам; строгое
>оставляет при равенстве того, кто встретился раньше.
Проверьте себя
Ответь сначала сам, потом открой ответ.
Начни с d = {"a": 1} и выполни d["b"] = 2, d["a"] += 5. Чему равен d и его длина?
ОтветСкрыть ответ
{'a': 6, 'b': 2}, длина 2.
Какие значения могут быть ключами словаря: (1, 2), [1, 2], "ab", 3.5, ([1],)?
ОтветСкрыть ответ
(1, 2), "ab" и 3.5.
Построй частотную таблицу букв слова "MISSISSIPPI".
ОтветСкрыть ответ
{'M': 1, 'I': 4, 'S': 4, 'P': 2}.
Что выведет print({1: "a", 1.0: "b", True: "c"})?
ОтветСкрыть ответ
{1: 'c'}: три равных ключа — один ключ, значение последнее.
Напиши программу: посчитай частоты слов в строке "кот дом кот сад дом кот" и выведи каждое слово с частотой.
ОтветСкрыть ответ
кот 3, дом 2, сад 1.
Напиши программу, которая «переворачивает» словарь {"a": 1, "b": 2}: ключи становятся значениями и наоборот.
ОтветСкрыть ответ
{1: 'a', 2: 'b'}.
Практика
Для проверки ответов нужен JavaScript. Условия, подсказки и решения доступны ниже.
Напиши программу: самое частое значение
Напиши программу: по списку она находит значение с наибольшей частотой и печатает его и частоту; при равенстве выбирается то, которое встретилось раньше. Запусти её для ['кот', 'дом', 'кот', 'сад', 'дом'] и для ['x', 'y', 'y', 'x'].
Запишите четыре значения через пробел: значение и частота для первого списка, затем для второго.
Подсказка
Сначала частотная таблица counts[item] = counts.get(item, 0) + 1, потом второй проход по counts.items() со строгим >.
Разбор
Например:
items = ['кот', 'дом', 'кот', 'сад', 'дом']counts = {}for item in items: counts[item] = counts.get(item, 0) + 1best_item = Nonebest_count = 0for item, count in counts.items(): if count > best_count: best_item = item best_count = countprint(best_item, best_count)«кот» и «дом» встречаются по 2 раза, раньше появился «кот». Во втором списке x и y — по 2, раньше x.
Ответ: кот 2 x 2
Что напечатает программа?
print({"a": 1}.get("z", 0))print("1" in {1: "x"})Запишите напечатанные строки через пробел в порядке вывода.
Подсказка
get с запасным значением не останавливает программу. in проверяет ключи, а строка «1» — не число 1.
Разбор
Ключа «z» нет — get даёт запасное 0. Ключ словаря — число 1, а проверяется строка «1»: False.
Ответ: 0 False
Что напечатает программа?
d = {"x": 3, "y": 5}total = 0for value in d.values(): total += valueprint(total)Введите число.
Подсказка
.values() перебирает значения словаря, а не ключи.
Разбор
Значения 3 и 5, сумма 8.
Ответ: 8