К содержанию

Модуль 4 · Урок 4.4

Словари и подсчёт частот

Доступ по смысловому ключу, обход пар и частотная таблица.

3 задачи

В списке значение ищут по номеру позиции. Но часто нужен ответ на другой вопрос: какой балл у Анны, сколько раз встретилась буква A. Словарь находит значение по смысловому ключу — имени, слову, букве — и поэтому естественно хранит частоты. Частотная таблица — это много счётчиков из урока о while сразу, по одному на каждое значение.

Работать будем с баллами учеников {"Анна": 91, "Илья": 84} и словом "BANANA", в котором посчитаем буквы.

Словарь

Словарь хранит пары «ключ — значение» и ищет значение по ключу. В списке элемент ищут по позиции. Иногда нужен доступ по имени: «балл Анны», «количество буквы A». Словарь (dict) хранит соответствия между ключами и значениями.

scores = {"Анна": 91, "Илья": 84}print(scores["Анна"])scores["Марк"] = 88scores["Анна"] = 95print(scores)
91 {'Анна': 95, 'Илья': 84, 'Марк': 88}

Ключ уникален: новое присваивание тому же ключу заменяет его значение. Значения могут повторяться. Чтение отсутствующего ключа через квадратные скобки вызывает ошибку:

scores = {"Анна": 91, "Илья": 84}print(scores["Ольга"])
KeyError: 'Ольга'

Безопасное чтение и проверка ключа:

scores = {"Анна": 91, "Илья": 84}print(scores.get("Ольга", 0))print("Анна" in scores)print(91 in scores)
0 True False

get(key, default) возвращает значение либо указанное значение по умолчанию; ключ от этого не добавляется. Без второго аргумента значение по умолчанию — None. Операция in для словаря проверяет ключи, а не значения: 91 есть среди значений, но ключом не является.

Какие бывают ключи

Ключом может быть число, строка или кортеж из них; список — нельзя. Ключ не должен меняться, пока лежит в словаре, поэтому изменяемые значения — список, словарь, множество — ключами быть не могут:

d = {[1, 2]: 3}
TypeError: cannot use 'list' as a dict key (unhashable type: 'list')
Тонкости:хеш и хешируемые значения

Для быстрого поиска словарь вычисляет по ключу число — хеш — и по нему сразу находит место хранения, не перебирая все пары. Если бы ключ изменился, изменился бы и хеш, и пара потерялась бы. Значения, у которых есть хеш, называют хешируемыми: числа, строки, кортежи из таких значений. Кортеж, содержащий список, не годится: список внутри него может измениться.

Значения словаря такими ограничениями не связаны: можно хранить под именем пользователя целый список его результатов.

Обход словаря

Словарь обходят по ключам или по парам; порядок — порядок добавления.

scores = {"Анна": 91, "Илья": 84}for name in scores:    print(name) total = 0for name, score in scores.items():    print(name, score)    total += scoreprint(total)
Анна Илья Анна 91 Илья 84 175

.items() позволяет получать пары, .keys() — ключи, .values() — значения; list(scores) создаёт список ключей.

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

Частотная таблица

Частотная таблица — словарь «значение → сколько раз встретилось». Частота — число появлений значения. Пройдём по буквам и увеличим соответствующий счётчик. Нажми «Запуск» и пройди подсчёт по шагам: на каждой итерации for берёт очередную букву, а следующая строка увеличивает её счётчик:

text = "BANANA"counts = {}for letter in text:    counts[letter] = counts.get(letter, 0) + 1print(counts)
{'B': 1, 'A': 3, 'N': 2}

Если буква встретилась впервые, get даёт 0. После прибавления записывается 1. При следующих появлениях читается накопленное значение: для первой A get даёт 0, и в словаре появляется 'A': 1, а для второй A — уже 1, и запись становится 'A': 2.

Каждая буква прибавляет 1 к своему ключу. Ключи стоят в порядке первого появления: B, затем A, затем N. После любой буквы в словаре лежат точные частоты уже пройденной части слова.

Самое частое значение

Самое частое значение находят вторым проходом по парам словаря. По списку ['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)
a 3

Строгое > оставляет прежнего победителя при равенстве. Порядок словаря совпадает с порядком первых появлений. Для пустого входа ответ остаётся 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 для каждого значения.
  • Самое частоеВторой проход по парам; строгое > оставляет при равенстве того, кто встретился раньше.

Проверьте себя

Ответь сначала сам, потом открой ответ.

Вопрос 1

Начни с d = {"a": 1} и выполни d["b"] = 2, d["a"] += 5. Чему равен d и его длина?

ОтветСкрыть ответ
Ответ

{'a': 6, 'b': 2}, длина 2.

Вопрос 2

Какие значения могут быть ключами словаря: (1, 2), [1, 2], "ab", 3.5, ([1],)?

ОтветСкрыть ответ
Ответ

(1, 2), "ab" и 3.5.

Вопрос 3

Построй частотную таблицу букв слова "MISSISSIPPI".

ОтветСкрыть ответ
Ответ

{'M': 1, 'I': 4, 'S': 4, 'P': 2}.

Вопрос 4

Что выведет print({1: "a", 1.0: "b", True: "c"})?

ОтветСкрыть ответ
Ответ

{1: 'c'}: три равных ключа — один ключ, значение последнее.

Вопрос 5

Напиши программу: посчитай частоты слов в строке "кот дом кот сад дом кот" и выведи каждое слово с частотой.

ОтветСкрыть ответ
Ответ

кот 3, дом 2, сад 1.

Вопрос 6

Напиши программу, которая «переворачивает» словарь {"a": 1, "b": 2}: ключи становятся значениями и наоборот.

ОтветСкрыть ответ
Ответ

{1: 'a', 2: 'b'}.

Практика

Для проверки ответов нужен JavaScript. Условия, подсказки и решения доступны ниже.

Напиши программу: самое частое значение

Напиши программу: по списку она находит значение с наибольшей частотой и печатает его и частоту; при равенстве выбирается то, которое встретилось раньше. Запусти её для ['кот', 'дом', 'кот', 'сад', 'дом'] и для ['x', 'y', 'y', 'x'].

Запишите четыре значения через пробел: значение и частота для первого списка, затем для второго.

Что напечатает программа?

print({"a": 1}.get("z", 0))print("1" in {1: "x"})

Запишите напечатанные строки через пробел в порядке вывода.

Что напечатает программа?

d = {"x": 3, "y": 5}total = 0for value in d.values():    total += valueprint(total)

Введите число.