The Messy Pipeline

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

Domain
Python
Difficulty
easy
Seniority
L4
Asked in
eHealth

Problem

Our upstream sensor export arrives as a data list that mixes plain numbers, the same numbers written as strings, None gaps, and the occasional batch of readings wrapped in its own inner list. Turn it into one flat list of every reading scaled by multiplier, kept in the order the readings arrive.

The upstream API has no idea what a schema is.

Example

Input:

data = [1,"2",[3,4],null,"5"], multiplier = 2

Output:

[2,4,6,8,10]

Worked solution and explanation

What this really is

This is a type-dispatch problem dressed up as a data cleanup. The skill being probed: can you look at each item and decide, before you touch it, whether it is a gap, a batch, or a scalar? A one-liner float(x) * multiplier over the raw list blows up on the first None or inner list, so the dispatch is not optional. Everyone gets the multiply right. What separates candidates is what they quietly lose: filter to int and float and every reading that arrived as '2' disappears with no error, turn None into 0.0 and you invent measurements nobody took, or sort the result to make it look tidy and the readings no longer line up with the order the export sent them.

Walking it through

Step 1: Drop the gaps first

None means no reading was taken, so it leaves the stream entirely. Checking item is None first also keeps it away from float(), which would raise on it.

Step 2: Open the batches one level

An inner list is a batch, not a value. isinstance(item, list) routes it into a second loop that scales each reading inside it. One level is all the export produces, so there is no recursion to build.

Step 3: Coerce everything else with one call

Everything left is a number or a numeric string, and float() accepts both. That is why there is no separate string branch: the conversion already handles '5' and 5 identically, and it guarantees a float even when the input was an int.

Step 4: Return in the order you met them

Appending as you walk preserves arrival order for free. There is nothing to reorder at the end, so the function returns scaled exactly as it was built.

Dispatch, coerce, scale
def coerce_and_flatten(data: list, multiplier: float) -> list[float]:
    scaled = []
    for item in data:
        if item is None:
            continue
        if isinstance(item, list):
            for reading in item:
                scaled.append(float(reading) * multiplier)
        else:
            scaled.append(float(item) * multiplier)
    return scaled

One pass over data; each inner batch is opened exactly once.

Filter to numbers
if isinstance(item, (int, float)) keeps 1 and drops '2' and '5'. The output for the example is three values instead of five, and nothing raises to tell you.
Coerce what you can
Skip None, open lists, and hand everything else to float(). The numeric strings become readings, and the output has all five values.

Common follow-up questions