The Intervals

A medium Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.

Domain
Python
Difficulty
medium
Seniority
L3
Asked in
Uber

Problem

You're rolling up a table of activity dates (ISO 'YYYY-MM-DD' strings, unsorted and sometimes repeated) into a weekly view. Group the dates into consecutive 7-day windows anchored on the earliest date, where the first window covers that date through the sixth day after it and each later window spans the next seven days. Return each populated window's 1-based number mapped to the dates that fell in it.

Timestamps in buckets.

Example

Input:

dates = ["2024-01-03","2024-01-08","2024-01-01","2024-01-15","2024-01-14"]

Output:

{"1":["2024-01-03","2024-01-01"],"2":["2024-01-08","2024-01-14"],"3":["2024-01-15"]}

Worked solution and explanation

What this problem really is

Strip the calendar dressing and this is fixed-width bucketing where the bucket origin is hidden in the data: week 1 doesn't start on a Monday or on New Year's, it starts on whatever the earliest date in the input happens to be. Two moves separate the candidates who pass. First, you cannot label a single date until you've seen the whole list, because the anchor is the minimum, so this is a two-pass problem no matter how you dress it. Second, the tempting move of sorting the dates so the buckets come out tidy is exactly the move that fails: the spec keeps each bucket in the order the dates arrived, and a sort silently reorders them. Get either wrong and every test that isn't already sorted comes back different.


The two passes you can't avoid

Step 1: Find the anchor without sorting

You cannot assign week numbers while you still don't know where week 1 begins, and week 1 begins at the earliest date. So scan once to find that anchor. Do NOT sort to get it: sorting is the one shortcut that destroys the within-bucket order the spec demands. Take min() over the parsed dates and leave the original list untouched.

Step 2: Convert each date to a stable day index

Parse each date once with datetime.strptime under the exact 'YYYY-MM-DD' contract, then use toordinal() to get an integer day count. Integer arithmetic on ordinals sidesteps the timezone and DST traps that bite candidates who try timedelta math, and it makes the offset a plain subtraction.

Step 3: Map the offset to a 1-indexed week label

For each date in ITS ORIGINAL position, compute (ordinal - anchor) // 7 + 1 and stringify it for the key. Use setdefault so the first date in a week creates the list and the rest append to it. Because you iterate the input in order and never sorted, each bucket ends up in arrival order for free, and empty windows simply never get a key.


The solution

Anchor on the min, iterate in place, integer-divide by 7
from datetime import datetime

def the_intervals(dates):
    if not dates:
        return {}
    ordinals = [datetime.strptime(d, '%Y-%m-%d').toordinal() for d in dates]
    anchor = min(ordinals)
    buckets = {}
    for date_str, ordinal in zip(dates, ordinals):
        week = (ordinal - anchor) // 7 + 1
        buckets.setdefault(str(week), []).append(date_str)
    return buckets
Sort first (wrong)
sorted(dates) makes buckets chronological, so an unsorted week comes back reordered. The visible test passes only because its input happened to be sorted; the moment a date arrives out of order, the bucket contents no longer match.
Iterate in place (right)
Anchor on min() and walk the original list. Each week keeps its arrival order, duplicates stay adjacent as given, and the answer is identical whether the input was tidy or shuffled.

Common follow-up questions