Перейти к содержимому
Теория · Словари и множества · урок 6 из 11

Подсчёт со словарём

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

Для каждой продажи он ищет на табличке строку с названием фрукта и прибавляет к её счёту единицу. Если такой строки ещё нет, он сначала пишет название и считает от нуля.

В Python это задача для словаря: ключ — слово, значение — счётчик. Когда слово попадается впервые, его ещё нет в словаре. Метод get со вторым аргументом 0 закрывает этот случай:

Python
words = ["red", "blue", "red", "green", "red"]
counts = {}
for w in words:
    counts[w] = counts.get(w, 0) + 1
print(counts)  # {'red': 3, 'blue': 1, 'green': 1}

Как работает строка подсчёта

Вся работа происходит в одной строке цикла. Строка counts[w] = counts.get(w, 0) + 1 делает три вещи по порядку:

  1. counts.get(w, 0) читает старый счёт слова, а для нового слова даёт 0.
  2. + 1 прибавляет к нему единицу.
  3. counts[w] = … записывает результат обратно под тот же ключ.

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

Нажмите «Следующий шаг» и следите за counts: новый ключ появляется со счётом 1, а знакомый растёт на единицу.

ВживуюПодсчёт через getшаг 1 из 9 · рамок: 1

Список продаж за день: груша, слива и снова груша.

Следите за counts после каждой строки 4

Почему нельзя написать counts[name] вместо get? Квадратные скобки читают ключ, а на первом шаге ключа 'pear' ещё нет. Чтение остановило бы программу ошибкой KeyError, а get в этом случае спокойно возвращает 0.

Counter

Модуль collections входит в Python и содержит готовые разновидности словаря. Его подключают строкой import collections, как math. collections.Counter считает элементы списка за один вызов — как продавец, которому табличку уже заполнили:

Python
import collections

words = ["red", "blue", "red", "green", "red"]
counts = collections.Counter(words)
print(counts["red"], counts["black"])  # 3 0
print(counts.most_common(2))  # [('red', 3), ('blue', 1)]

Давайте разберём по строкам:

  1. collections.Counter(words) проходит по списку и строит словарь счётчиков.
  2. counts["red"] даёт 3, а counts["black"] — 0: отсутствующий ключ у Counter даёт 0, а не KeyError.
  3. counts.most_common(2) возвращает список из двух пар «элемент — счёт» от большего счёта к меньшему.

Counter — это словарь: у него есть get, items и чтение по ключу. При равном счёте most_common первым ставит элемент, который встретился раньше, поэтому 'blue' стоит перед 'green'. Считать можно и символы строки: в collections.Counter("hello") под ключом 'l' стоит 2.

defaultdict

Иногда под ключом копится не число, а список, например слова на одну букву. collections.defaultdict(list) при чтении отсутствующего ключа вызывает list(), кладёт под ключ пустой список и возвращает его. В скобках стоит сама функция list без вызова: словарь вызывает её, когда ему нужен новый пустой список.

Python
import collections

words = ["apple", "bean", "avocado", "beet", "corn"]
groups = collections.defaultdict(list)
for w in words:
    groups[w[0]].append(w)
print(groups["a"])  # ['apple', 'avocado']
print(len(groups))  # 3

Разберём цикл:

  1. w[0] — первая буква слова: "a", "b" или "c".
  2. groups[w[0]] для новой буквы создаёт пустой список, а для знакомой возвращает уже накопленный.
  3. .append(w) дописывает слово в этот список.

defaultdict(int) так же создаёт 0, ведь int() возвращает 0. Счётчик из первого примера тогда пишется как counts[w] += 1. Ключ появляется даже от одного чтения: groups["z"] добавит пару с пустым списком. Проверять наличие ключа поэтому нужно через in.

Этот вопрос часто задают на собеседовании: «Как посчитать, сколько раз встречается каждый элемент списка?» Хороший ответ называет три способа:

  • обычный словарь и counts[x] = counts.get(x, 0) + 1;
  • collections.Counter(items) — один вызов, плюс most_common;
  • collections.defaultdict(int) и counts[x] += 1.

Частая ошибка

Счёт увеличивают через += в обычном словаре:

Python
words = ["red", "blue", "red"]
counts = {}
for w in words:
    counts[w] += 1  # ✗
TEXT
KeyError: 'red'

Запись counts[w] += 1 сначала читает counts[w], а при первой встрече слова ключа ещё нет. Это как прибавить единицу к строке, которой на табличке нет. Используйте get с 0, Counter или defaultdict(int).

Главное

  • counts[k] = counts.get(k, 0) + 1 читает старый счёт или 0 и записывает его на единицу больше.
  • counts[k] += 1 в обычном словаре вызывает KeyError на новом ключе.
  • Counter считает элементы одним вызовом и даёт 0 для отсутствующего ключа.
  • defaultdict(list) и defaultdict(int) сами создают значение для нового ключа.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом