📖 Теория: Анализ продаж по категориям и датам

⚡ Кратко

Задача — обработать текстовый файл с продажами и создать отчёты. Каждая строка файла содержит имя,дата,сумма,категория,город.

Программа принимает два аргумента командной строки: путь к входному файлу и папку для отчётов.

Группировка выполняется через defaultdict: одна структура хранит записи по (год, месяц, категория), другая — суммы по (год, месяц) и категориям.

Для каждого года и месяца создаётся папка reports/YYYY/MM/ с файлом monthly_report.txt и файлами по категориям.

Постановка задачи

Напишите программу sales_report.py, которая обрабатывает текстовый файл с данными о продажах и формирует структуру отчётов на диске.

Программа запускается из командной строки:

python sales_report.py <input_file> <output_directory>
  • <input_file> — путь к файлу sales_data.txt с записями о продажах.
  • <output_directory> — папка, в которой будут созданы отчёты.

Формат входных данных

Каждая строка входного файла содержит пять полей, разделённых запятой:

имя,дата,сумма,категория,город

Пример строк:

Olivia Suarez,2024-08-02,4565,Electronics,Dallas
Jennifer Jacobs,2023-08-19,4963,Automotive,London
Erin Johnson,2024-08-29,1796,Clothing,Miami

Из даты 2024-08-02 нужно выделить год 2024 и месяц 08, чтобы сгруппировать запись по периоду.

Формат выходных данных

Для каждого года и месяца программа должна создать папку output_directory/YYYY/MM/. Внутри папки размещаются:

  • monthly_report.txt — общий отчёт с суммарной выручкой по каждой категории и общей суммой.
  • Файлы <category>.txt — списки продаж по категории в формате дата,имя продавца,сумма, отсортированные по дате.

Пример monthly_report.txt:

Automotive,109539
Books,133160
Clothing,102001
Electronics,79403
Groceries,104387
Home Appliances,99911
Sports,78782
Full,707183

Пример файла Electronics.txt:

2025-02-01,Cynthia Maddox,538
2025-02-01,Kendra Martinez,3799
2025-02-02,Rachel Miller,1097

Пример созданной структуры

reports/
├── 2024/
│   ├── 12/
│   │   ├── monthly_report.txt
│   │   ├── Automotive.txt
├── 2025/
│   ├── 01/
│   │   ├── monthly_report.txt
│   │   ├── Clothing.txt
│   │   ├── Electronics.txt
│   ├── 02/
│   │   ├── monthly_report.txt
│   │   ├── Groceries.txt
│   │   ├── Sports.txt

План решения

  1. Прочитать аргументы командной строки. Использовать sys.argv и проверить, что передано два аргумента. Иначе вывести подсказку и завершить программу.
  2. Прочитать и распарсить файл. Открыть файл в кодировке utf-8, прочитать строки, разбить каждую по ,, проверить количество полей и преобразовать сумму в int.
  3. Сгруппировать данные. Использовать defaultdict(list) для записей по (year, month, category) и defaultdict(lambda: defaultdict(int)) для сумм по категориям внутри каждого (year, month).
  4. Создать файлы по категориям. Для каждой группы (year, month, category) отсортировать записи по дате, создать папки и записать строки в файл <category>.txt.
  5. Создать месячные отчёты. Для каждого (year, month) записать суммы по категориям в monthly_report.txt и добавить строку Full,<total> с общей суммой.

Почему defaultdict

Без defaultdict при каждом обращении к новому ключу пришлось бы проверять, есть ли он в словаре:

if key not in grouped:
    grouped[key] = []
grouped[key].append(record)

С defaultdict(list) этот код сокращается до одной строки:

grouped[key].append(record)

Аналогично для вложенной группировки сумм: defaultdict(lambda: defaultdict(int)) автоматически создаёт внутренний счётчик для каждой новой категории.

Почему os.path.join

Разделители в путях различаются на Windows (\) и Unix (/). Если писать путь вручную, программа может не работать на другой операционной системе. os.path.join выбирает правильный разделитель автоматически.

report_file = os.path.join(output_dir, year, month, "monthly_report.txt")

Краткий итог

Практикум объединяет несколько важных навыков: чтение аргументов командной строки, парсинг текстового файла, группировку через defaultdict, создание директорий и запись отчётов. В результате получается полноценная утилита для обработки данных.