← все задачи
Python · задача 1 из 10
Сгруппировать записи по полю
Начальный
10 минут
словариdefaultdictкраевые случаи
Условие
Есть список заказов, у каждого есть customer_id и сумма. Напишите функцию, которая вернёт словарь: клиент — список его заказов. Затем — вариант, который вернёт сумму заказов по каждому клиенту.
Что требуется
- На вход — список словарей произвольной длины
- Порядок заказов внутри клиента сохраняется
- Пустой список — пустой результат, без исключения
Пример
orders = [
{"customer_id": 1, "amount": 100},
{"customer_id": 2, "amount": 50},
{"customer_id": 1, "amount": 30},
]
group_by_customer(orders)
# {1: [{...100}, {...30}], 2: [{...50}]}
total_by_customer(orders)
# {1: 130, 2: 50}
Сначала уточните
Вопросы до кода — половина оценки. Молча начать печатать хуже, чем задать два вопроса.
- Может ли customer_id отсутствовать в записи — пропускать такие или падать?
- Нужен ли порядок ключей в результате (тогда dict сохранит порядок появления)?
- Объём данных: помещается в память или это поток на миллионы строк?
Показать решение Скрыть решение
Решение
from collections import defaultdict
def group_by_customer(orders):
grouped = defaultdict(list)
for order in orders:
grouped[order["customer_id"]].append(order)
return dict(grouped)
def total_by_customer(orders):
totals = defaultdict(int)
for order in orders:
totals[order["customer_id"]] += order["amount"]
return dict(totals)
# Если группировать нужно по произвольному признаку:
def group_by(items, key):
grouped = defaultdict(list)
for item in items:
grouped[key(item)].append(item)
return dict(grouped)
Почему так
Почему defaultdict, а не dict.setdefault
- setdefault создаёт новый список на каждой итерации, даже когда он не нужен, — defaultdict делает это только при промахе
- Код читается как формула: «взять список этого клиента и добавить заказ», без служебной ветки
- dict(grouped) на выходе — чтобы наружу не утекал объект, который молча создаёт ключи при чтении: grouped[999] вернёт [] и добавит ключ
Почему не itertools.groupby
- groupby группирует только подряд идущие элементы — для несортированного списка он даст несколько групп на один ключ
- Чтобы им воспользоваться, список нужно сначала отсортировать: O(n log n) вместо O(n)
- Назвать это вслух — хороший ход: видно, что вы знаете инструмент и понимаете, почему он здесь не подходит
Что спросят дальше
- Спросят про отсутствующий ключ: order.get("customer_id") и явное решение — пропустить, положить в None-группу или упасть
- Спросят про большие данные: если это поток, показывайте генератор и агрегацию на лету, а не список в памяти
- Могут попросить топ-3 клиентов по сумме — это sorted(totals.items(), key=lambda kv: -kv[1])[:3] или heapq.nlargest
Следующая задача
Топ-N самых частых слов — Проверяют знание Counter и умение аккуратно обойтись с одинаковыми частотами.