The Narrow Lens

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
L5
Asked in
Sigmoid

Problem

Raw sensor values arrive in order and are smoothed before alerting by replacing each reading with the average of that reading and the ones just before it, at most window_size readings in all. A window_size below 1 means smoothing is switched off for the stream, and the result is an empty list.

A narrow timeframe. Everything inside matters.

Example 1

Input:

window_size = 3, values = [10,20,30,40,50]

Output:

[10,15,20,30,40]

Example 2

Input:

window_size = 2, values = [5,15,25]

Output:

[5,10,20]

Worked solution and explanation

Why this problem exists in real interviews

This is a trailing-average smoother wearing a sensor-stream costume, and the whole problem lives in one decision: what do you divide by? Everyone gets the full-window region right. What separates candidates is the warm-up region, the positions before the window has filled, where the correct divisor is how many readings you actually have, not the window size you were handed. Get that wrong and every early output comes back deflated, which on a real alerting pipeline means the first few minutes of every stream silently read low.


Break down the requirements

Step 1: Read the contract: stateless function, parallel output

The signature is the_narrow_lens(window_size, values) and it returns a list the same length as values. There is no class and no state carried across calls. One list in, one fully materialized list out, one trailing average per input position.

Step 2: Handle the warm-up region

At index i the divisor is the count of readings actually in the window, which is min(i + 1, window_size), not window_size. The positions before the window fills are warm-up and average every reading seen so far. Dividing by the full window size early returns deflated averages and fails the first visible test at index 0.

Step 3: Branch on warm-up versus full window

Split the positions in two. While i < window_size the window is the warm-up prefix values[:i + 1]; after that it is values[i - window_size + 1:i + 1], inclusive of position i and exactly window_size long. Branching this way also means the start index can never go negative, so Python's wrap-around slicing never pulls readings from the end of the list. Slicing to i instead of i + 1 shifts every average back one slot.

Step 4: Guard the window that holds nothing

A window_size below 1 means smoothing is off, and the statement asks for an empty list. Without the guard, a zero-size window slices out nothing and sum(window) / len(window) divides by zero. One early if window_size < 1 or not values: return [] settles it before the main path starts.


The solution

Stateless trailing average over the input list
def the_narrow_lens(window_size, values):
    # A window that holds no readings has no average to report.
    if window_size < 1 or not values:
        return []

    averages = []
    for i in range(len(values)):
        if i < window_size:
            # Warm-up: the window is everything seen so far.
            window = values[:i + 1]
        else:
            window = values[i - window_size + 1:i + 1]
        averages.append(sum(window) / len(window))
    return averages

Common follow-up questions