Коллекции стандартной библиотеки: deque, Counter, defaultdict и ChainMap
Содержание курса
Анализ частот и операции над мультимножествами с Counter
Когда нужно подсчитать, сколько раз встречаются элементы в последовательности, стандартным решением является collections.Counter. Это подкласс словаря dict, оптимизированный для подсчёта хешируемых объектов.
from collections import Counter
log_levels = ["INFO", "ERROR", "INFO", "WARNING", "ERROR", "ERROR"]
counts = Counter(log_levels)
print(counts)
print(counts.most_common(2))
Вывод программы:
Counter({'ERROR': 3, 'INFO': 2, 'WARNING': 1})
[('ERROR', 3), ('INFO', 2)]
Метод most_common(k) возвращает наиболее часто встречающихся элементов и их количество в виде пар кортежей, отсортированных по убыванию частоты. Если запросить ключ, которого нет в счётчике, Counter не выбросит KeyError, а вернёт 0.
Помимо подсчёта, Counter ведёт себя как мультимножество. Над ним определены бинарные операции со строгой математической семантикой для мультимножеств:
- Сложение
+: складывает количества повторений для каждого элемента. - Вычитание
-: вычитает счётчики второго мультимножества из первого. - Пересечение
&: берёт минимум счётчиков для общих элементов — . - Объединение
|: берёт максимум счётчиков — .
box_a = Counter(apples=3, oranges=1, bananas=4)
box_b = Counter(apples=1, oranges=5, kiwi=2)
print("box_a + box_b:", box_a + box_b)
print("box_a - box_b:", box_a - box_b)
print("box_a & box_b:", box_a & box_b)
print("box_a | box_b:", box_a | box_b)
Вывод программы:
box_a + box_b: Counter({'oranges': 6, 'apples': 4, 'bananas': 4, 'kiwi': 2})
box_a - box_b: Counter({'bananas': 4, 'apples': 2})
box_a & box_b: Counter({'apples': 1, 'oranges': 1})
box_a | box_b: Counter({'oranges': 5, 'bananas': 4, 'apples': 3, 'kiwi': 2})
Важнейшее правило операторов +, -, &, |: они возвращают новый Counter и автоматически отбрасывают все неположительные результаты (значения ). Например, при вычитании box_a - box_b для 'oranges' получается , поэтому ключ 'oranges' вообще не попадает в итоговый счётчик.
Если же вам требуется сохранить отрицательные балансы (например, для учёта дефицита на складе), используют метод subtract():
stock = Counter(apples=3, oranges=1)
order = Counter(apples=1, oranges=5)
stock.subtract(order)
print("Баланс после subtract():", stock)
Вывод программы:
Баланс после subtract(): Counter({'apples': 2, 'oranges': -4})
Метод subtract() мутирует существующий объект на месте и, в отличие от оператора -, честно сохраняет нулевые и отрицательные значения.
