Подсчёт со словарём
Представьте вечер на фруктовом прилавке. Продавец хочет узнать, сколько чего продал за день. У него есть список продаж и чистая табличка.
Для каждой продажи он ищет на табличке строку с названием фрукта и прибавляет к её счёту единицу. Если такой строки ещё нет, он сначала пишет название и считает от нуля.
В Python это задача для словаря: ключ — слово, значение — счётчик. Когда слово попадается впервые, его ещё нет в словаре. Метод get со вторым аргументом 0 закрывает этот случай:
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 делает три вещи по порядку:
counts.get(w, 0)читает старый счёт слова, а для нового слова даёт0.+ 1прибавляет к нему единицу.counts[w] = …записывает результат обратно под тот же ключ.
Для нового слова под ключом оказывается 1, а для знакомого — счёт на единицу больше прежнего. Ключ при этом не перемещается: новые слова встают в конец словаря в порядке первой встречи.
Нажмите «Следующий шаг» и следите за counts: новый ключ появляется со счётом 1, а знакомый растёт на единицу.
1sales = ["pear", "plum", "pear"]2counts = {}3for name in sales:4 counts[name] = counts.get(name, 0) + 15print(counts)
Список продаж за день: груша, слива и снова груша.
Почему нельзя написать counts[name] вместо get? Квадратные скобки читают ключ, а на первом шаге ключа 'pear' ещё нет. Чтение остановило бы программу ошибкой KeyError, а get в этом случае спокойно возвращает 0.
Counter
Модуль collections входит в Python и содержит готовые разновидности словаря. Его подключают строкой import collections, как math. collections.Counter считает элементы списка за один вызов — как продавец, которому табличку уже заполнили:
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)]Давайте разберём по строкам:
collections.Counter(words)проходит по списку и строит словарь счётчиков.counts["red"]даёт3, аcounts["black"]—0: отсутствующий ключ уCounterдаёт0, а неKeyError.counts.most_common(2)возвращает список из двух пар «элемент — счёт» от большего счёта к меньшему.
Counter — это словарь: у него есть get, items и чтение по ключу. При равном счёте most_common первым ставит элемент, который встретился раньше, поэтому 'blue' стоит перед 'green'. Считать можно и символы строки: в collections.Counter("hello") под ключом 'l' стоит 2.
defaultdict
Иногда под ключом копится не число, а список, например слова на одну букву. collections.defaultdict(list) при чтении отсутствующего ключа вызывает list(), кладёт под ключ пустой список и возвращает его. В скобках стоит сама функция list без вызова: словарь вызывает её, когда ему нужен новый пустой список.
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Разберём цикл:
w[0]— первая буква слова:"a","b"или"c".groups[w[0]]для новой буквы создаёт пустой список, а для знакомой возвращает уже накопленный..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.
Частая ошибка
Счёт увеличивают через += в обычном словаре:
words = ["red", "blue", "red"]
counts = {}
for w in words:
counts[w] += 1 # ✗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 и подпишись на канал — откроются все уроки.