2025, Oct 17 20:16
Единая временная шкала: сплющиваем словарь дат в Python
Пошагово показываем, как в Python сплющить словарь списков дат в список пар (метка, дата) и отсортировать его по составному ключу (дата, метка) с помощью lambda
Когда даты хранятся под разными ключами в отображении, часто нужна единая хронологическая последовательность по всем ключам. Задача — «сплющить» словарь, сопоставляющий метки со списками объектов даты, и получить отсортированный список кортежей (метка, дата), упорядоченный сначала по дате, а затем по метке. Ниже — минимальный воспроизводимый пример этой ситуации и устойчивый способ ее решить.
Постановка задачи
Данные приходят в виде составляющих месяц/день, из них собираются объекты даты и группируются по меткам. Цель — получить один отсортированный список пар.
from datetime import datetime, date
mon_x = [8, 9, 10]
day_x = [13, 12, 15]
mon_y = [8, 9, 10]
day_y = [13, 11, 13]
dates_x = []
for mm, dd in zip(mon_x, day_x):
    dates_x.append(datetime(2025, mm, dd).date())
dates_y = []
for mm, dd in zip(mon_y, day_y):
    dates_y.append(datetime(2025, mm, dd).date())
label_to_dates = {"A": dates_x, "B": dates_y}
print("original:")
print(label_to_dates)
expected_sorted = [
    ("A", date(2025, 8, 13)),
    ("B", date(2025, 8, 13)),
    ("B", date(2025, 9, 11)),
    ("A", date(2025, 9, 12)),
    ("B", date(2025, 10, 13)),
    ("A", date(2025, 10, 15)),
]
print("sorted:")
print(expected_sorted)
Что происходит и почему
Структура данных — словарь, в котором значениями выступают списки дат. Если сортировать эти списки по отдельности, единой временной линии для всех меток не получится. Рабочий подход — превратить структуру в единый список пар (метка, дата), а затем отсортировать его по ключу, который учитывает хронологию и при равных датах разрешает порядок по метке. Так задача распадается на два простых и предсказуемых шага: сформировать пары, затем их отсортировать.
Решение: сначала сплющивание, затем сортировка по составному ключу
Следующая функция за один проход собирает все пары и возвращает список, отсортированный сперва по дате, затем по метке. Реализация предельно прозрачна и явно фиксирует логику.
from datetime import datetime, date
def arrange_pairs(mapping: dict[str, list[date]]) -> list[tuple[str, date]]:
    pairs: list[tuple[str, date]] = []
    for lbl, seq in mapping.items():
        for dt in seq:
            pairs.append((lbl, dt))
    return sorted(pairs, key=lambda it: (it[1], it[0]))
mon_x = [8, 9, 10]
day_x = [13, 12, 15]
mon_y = [8, 9, 10]
day_y = [13, 11, 13]
dates_x: list[date] = []
for mm, dd in zip(mon_x, day_x):
    dates_x.append(datetime(2025, mm, dd).date())
dates_y: list[date] = []
for mm, dd in zip(mon_y, day_y):
    dates_y.append(datetime(2025, mm, dd).date())
label_to_dates = {"A": dates_x, "B": dates_y}
print(label_to_dates)
print(arrange_pairs(label_to_dates))
Ключ в lambda сортирует по второму элементу кортежа (дате) и использует метку как вторичный критерий, чтобы при равных датах порядок был детерминированным.
Если предпочитаете более компактную запись, ту же идею можно оформить одной функцией sorted поверх генератора, который сразу отдает пары напрямую.
result = sorted(
    ((k, d) for k, vals in label_to_dates.items() for d in vals),
    key=lambda t: (t[1], t[0])
)
Почему это важно
Сквозные хронологические представления по сгруппированным временным рядам встречаются повсюду: логи, метрики, события или входы ETL. Явное преобразование — сначала сплющивание в пары, затем сортировка — помогает избежать скрытых ошибок и делает конвейер понятнее. К тому же легко добавлять или корректировать правила разрешения совпадений, сохраняя общий ход обработки.
Выводы
Соберите единую последовательность пар (метка, дата), затем отсортируйте ее по составному ключу, где дата стоит первой. Такой подход делает намерение предельно ясным, а результат — стабильным. Даже если списки под каждой меткой уже упорядочены, это не снимает необходимости объединять и сортировать данные между метками: единый список все равно нужен, чтобы получить одну глобальную временную линию.