collections: Counter, defaultdict, deque и дедупликация
Готовые структуры из модуля collections и две частые задачи: частота элементов и дедупликация без потери порядка.
Модуль
collectionsдаёт специализированные контейнеры:Counter(счётчик),defaultdict(словарь со значением по умолчанию),deque(двусторонняя очередь).
Задача: частота слов через Counter
Чёткий ответ. Counter из модуля collections считает вхождения автоматически, а most_common(n) возвращает n самых частых элементов уже отсортированными.
from collections import Counter
text = "ля ля фа ля фа соль фа"
words = text.split()
freq = Counter(words)
print(freq)
print("топ-2:", freq.most_common(2))
Вывод:
Counter({'ля': 3, 'фа': 3, 'соль': 1})
топ-2: [('ля', 3), ('фа', 3)]
Counter для символов
Тот же приём работает для любой последовательности — например, посчитать буквы в слове.
from collections import Counter
print(Counter("mississippi"))
print(Counter("mississippi").most_common(2))
Вывод:
Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})
[('i', 4), ('s', 4)]
defaultdict: группировка без проверок
Обычный словарь бросает KeyError при доступе к несуществующему ключу. defaultdict(list) сам создаёт пустой список для нового ключа — идеально для группировки, избавляя от if key not in d: d[key] = [].
from collections import defaultdict
groups = defaultdict(list)
for word in ["apple", "banana", "avocado", "cherry"]:
groups[word[0]].append(word) # ключа ещё нет — создастся []
print(dict(groups))
Вывод:
{'a': ['apple', 'avocado'], 'b': ['banana'], 'c': ['cherry']}
Задача: дедупликация с сохранением порядка
Просто set() убирает дубликаты, но теряет порядок. Чтобы сохранить порядок первого появления, ведут множество «уже виденных» — или используют тот факт, что словарь с Python 3.7 хранит порядок вставки.
def dedup(seq):
seen = set()
result = []
for x in seq:
if x not in seen:
seen.add(x)
result.append(x)
return result
data = [3, 1, 2, 1, 3, 4, 2]
print("вручную: ", dedup(data))
# короткий идиоматичный способ — dict.fromkeys хранит порядок вставки
print("fromkeys: ", list(dict.fromkeys(data)))
Вывод:
вручную: [3, 1, 2, 4] fromkeys: [3, 1, 2, 4]
dict.fromkeys создаёт словарь с уникальными ключами в порядке их первого появления; превратив его ключи в список, получаем дедупликацию с сохранением порядка одной строкой.
deque: быстрая очередь с двух концов
У списка pop(0) и insert(0, x) работают за O(n). deque добавляет и удаляет с обоих концов за O(1) — правильный выбор для очередей и стеков.
from collections import deque
dq = deque([1, 2, 3])
dq.appendleft(0) # O(1) слева
dq.append(4) # O(1) справа
print(dq)
print("слева:", dq.popleft(), "справа:", dq.pop())
print(dq)
Вывод:
deque([0, 1, 2, 3, 4]) слева: 0 справа: 4 deque([1, 2, 3])
Итог
Counter(iterable)считает частоты за один проход;most_common(n)отдаёт самые частые.defaultdict(list)избавляет от проверок ключа при группировке.deque— очередь сO(1)на обоих концах; дедупликацию с порядком даётlist(dict.fromkeys(seq)).