2025, Oct 17 20:00
Flatten a label-to-dates mapping in Python and sort (label, date) tuples by date, then label
Learn how to flatten a Python dictionary of date lists into (label, date) pairs and sort them by date then label using a composite key. Clear code and examples.
When dates are stored under different keys in a mapping, you often need a single chronological sequence across all keys. The task is to flatten a dictionary that maps labels to lists of date objects and produce a sorted list of (label, date) tuples, ordered first by date and then by label. Below is a minimal, reproducible setup of that scenario and a robust way to solve it.
Problem setup
The data comes as month/day components, which are combined into date objects and grouped by labels. The goal is to end up with a single sorted list of pairs.
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)
What’s going on and why it happens
The data structure is a dictionary whose values are lists of dates. Sorting those lists in isolation does not produce one coherent timeline across all labels. The practical path is to flatten the structure into a single list of (label, date) pairs and then sort that list with a key that respects chronological order and resolves ties by label. This turns the problem into two small, predictable steps: build the pairs, then sort them.
Solution: flatten then sort with a composite key
The following function collects all pairs in one pass and returns a list sorted by date first and by label second. The implementation keeps the logic straightforward and explicit.
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))
The key lambda sorts by the second element of the tuple (the date) and uses the label as a secondary key for deterministic ordering when dates are equal.
If you prefer a compact expression, the same idea can be written as a single sorted call over a generator that yields the pairs directly.
result = sorted(
    ((k, d) for k, vals in label_to_dates.items() for d in vals),
    key=lambda t: (t[1], t[0])
)
Why this matters
Chronological views across grouped time series appear everywhere: logs, metrics, events, or ETL inputs. Keeping the transformation explicit—first flattening to pairs, then sorting—avoids subtle mistakes and keeps the pipeline readable. It also makes it easy to add or adjust tie-breakers while preserving the overall flow.
Takeaways
Build a single sequence of (label, date) pairs, then sort by a composite key that puts the date first. This approach keeps the intent crystal-clear and the result stable. If the lists under each label are already in order, it doesn’t remove the need to merge and sort across labels; the unified list is still required to establish one global timeline.