Модуль collections: Counter, defaultdict, deque

⏱ 30 мин · 🧩 заданий: 5

Counter — подсчёт

Counter — словарь «элемент → количество».

from collections import Counter

c = Counter("абракадабра")
print(c)
print(c["а"], c["я"])              # отсутствующий элемент — 0, а не KeyError
print(c.most_common(2))

words = "to be or not to be that is".split()
wc = Counter(words)
wc.update(["be", "be"])            # добавить ещё
print(wc.most_common(3))
print(sum(wc.values()), len(wc))   # всего слов, уникальных

Counter поддерживает арифметику:

from collections import Counter
inventory = Counter(apples=5, pears=2)
sold = Counter(apples=3, pears=2)
print(inventory - sold)            # отрицательные и нулевые отбрасываются
print(inventory + sold, inventory & sold, inventory | sold)
print(list((inventory + sold).elements()))

defaultdict — значение по умолчанию

defaultdict(фабрика) при обращении к отсутствующему ключу вызывает фабрику и вставляет результат:

from collections import defaultdict

groups = defaultdict(list)
for name, dept in [("Анна", "IT"), ("Борис", "HR"), ("Вера", "IT")]:
    groups[dept].append(name)        # без проверки «есть ли ключ»
print(dict(groups))

counts = defaultdict(int)            # int() == 0
for ch in "hello":
    counts[ch] += 1
print(dict(counts))

graph = defaultdict(set)
for a, b in [(1, 2), (1, 3), (2, 3)]:
    graph[a].add(b)
    graph[b].add(a)
print(dict(graph))

Чтение тоже создаёт ключ

groups["нет такого"] не бросит ошибку, а добавит пустой список. Для проверки используйте "ключ" in groups или groups.get("ключ").

deque — двусторонняя очередь

deque (произносится «дек») — быстрые O(1) операции с обоих концов.

from collections import deque

q = deque([1, 2, 3])
q.append(4)          # в конец
q.appendleft(0)      # в начало
print(q.pop(), q.popleft(), q)
q.rotate(1)          # циклический сдвиг вправо
print(q)

recent = deque(maxlen=3)      # хранит только последние 3
for page in ["/", "/about", "/blog", "/contacts"]:
    recent.append(page)
print(recent)

Очередь задач (FIFO) и обход графа в ширину (BFS) пишут именно на deque:

from collections import deque

def bfs_order(graph, start):
    seen, order, queue = {start}, [], deque([start])
    while queue:
        node = queue.popleft()
        order.append(node)
        for nxt in graph[node]:
            if nxt not in seen:
                seen.add(nxt)
                queue.append(nxt)
    return order

g = {"A": ["B", "C"], "B": ["D"], "C": ["D"], "D": []}
print(bfs_order(g, "A"))
Операция list deque
добавить / удалить в конце O(1) O(1)
добавить / удалить в начале O(n) O(1)
доступ по индексу x[i] O(1) O(n) в середине

namedtuple

Кортеж с именованными полями (подробнее — в уроке «Кортежи»):

from collections import namedtuple
Point = namedtuple("Point", "x y")
p = Point(1, 2)
print(p.x + p.y, p._replace(x=10), Point._fields)

OrderedDict

Обычный dict уже хранит порядок, но у OrderedDict есть move_to_end и popitem(last=False) — готовая основа для LRU-кеша (частая задача на собеседовании):

from collections import OrderedDict

class LRUCache:
    def __init__(self, capacity):
        self.capacity = capacity
        self.data = OrderedDict()

    def get(self, key):
        if key not in self.data:
            return -1
        self.data.move_to_end(key)          # недавно использованный — в конец
        return self.data[key]

    def put(self, key, value):
        self.data[key] = value
        self.data.move_to_end(key)
        if len(self.data) > self.capacity:
            self.data.popitem(last=False)   # вытеснить самый старый

cache = LRUCache(2)
cache.put("a", 1); cache.put("b", 2)
cache.get("a")                 # теперь "b" — самый старый
cache.put("c", 3)              # вытесняет "b"
print(list(cache.data.items()), cache.get("b"))

ChainMap — слои словарей

Ищет ключ по очереди в нескольких словарях — удобно для настроек «аргументы командной строки → переменные окружения → значения по умолчанию»:

from collections import ChainMap
defaults = {"debug": False, "port": 8000}
env = {"port": 9000}
cli = {"debug": True}
config = ChainMap(cli, env, defaults)
print(config["debug"], config["port"], dict(config))

Итог

  • Counter — подсчёт, most_common, арифметика.
  • defaultdict(list/int/set) — группировка и подсчёт без проверок ключа.
  • deque — очередь с O(1) с обоих концов, maxlen для «последних N»; BFS.
  • namedtuple — кортеж с полями; OrderedDict — move_to_end для LRU; ChainMap — слои настроек.

Практика решено 0 из 5

Вы не вошли — ответы проверяются, но прогресс не сохранится. Войти или зарегистрироваться.
Задание 1 Программа на Python

Напишите функцию top_words(text, n), которая возвращает список из n самых частых слов (в нижнем регистре) в виде пар (слово, количество). Используйте Counter.most_common.

Какие тесты проверяют код (2)
assert top_words("a b a c b a", 2) == [("a", 3), ("b", 2)]
assert top_words("Кот кот пёс", 1) == [("кот", 2)]
Задание 2 Программа на Python

Напишите функцию is_anagram(a, b): проверить, что строки состоят из одних и тех же букв с учётом количества (регистр и пробелы не учитывать).

Какие тесты проверяют код (3)
assert is_anagram("Listen", "Silent") is True
assert is_anagram("aab", "abb") is False
assert is_anagram("кабан", "банка") is True
Задание 3 Программа на Python

Напишите функцию group_by_first_letter(words), которая возвращает defaultdict(list) «первая буква → список слов».

Какие тесты проверяют код (2)
r = group_by_first_letter(["арбуз", "банан", "абрикос"]); assert r == {"а": ["арбуз", "абрикос"], "б": ["банан"]}
assert isinstance(group_by_first_letter([]), defaultdict)
Задание 4 Программа на Python

Напишите функцию moving_average(nums, k), которая возвращает список средних значений каждого окна из k подряд идущих чисел. Используйте deque(maxlen=k) и текущую сумму окна.

Какие тесты проверяют код (3)
assert moving_average([1, 2, 3, 4, 5], 2) == [1.5, 2.5, 3.5, 4.5]
assert moving_average([1, 2, 3], 3) == [2.0]
assert moving_average([1, 2], 3) == []
Задание 5 Один вариант ответа

Почему для очереди (добавить в конец, забрать из начала) используют deque, а не list?

Войдите, чтобы отмечать пройденные уроки.