The Flat Mapper
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
- L3
- Asked in
- eHealth
Problem
Our downstream aggregator keeps rejecting the metrics export because some entries in items are a single integer reading while others are a list of readings a device sent together. Unpack it into one flat list of every reading in the order they were exported; a bundle only ever holds integers, never another bundle.
Nested values. One flat stream out.
Example
Input:
items = [1,[2,3],4,[5,6,7]]
Output:
[1,2,3,4,5,6,7]
Worked solution and explanation
This is a per-entry type check dressed up as a flatten. Everyone knows how to splice lists together; what is being probed is whether you notice the top level is heterogeneous. The reflex one-liner [x for sub in items for x in sub] (or sum(items, [])) assumes every entry is iterable, so the first lone reading raises TypeError: 'int' object is not iterable. The loader then dies on exactly the exports that caused the complaint.
Two kinds of entry, one pass
Step 1: Walk items once, left to right
The output order is the export order, so you emit into a single result as you go. There is no sorting and no second pass, and nothing to reconcile at the end.
Step 2: Decide per entry: bundle or reading
isinstance(item, list) is the whole problem. A bundle has its readings spliced in exactly where it sat. A bare reading goes in as-is. Skip this check and either the integers crash you or you wrap them in something they never were.
Step 3: Let empty bundles fall out on their own
An empty bundle like [] contributes nothing because the inner loop runs zero times. No special case is needed, and adding one is a tell that you have not traced the loop.
def flat_map_one_level(items: list) -> list[int]:
readings = []
for item in items:
if isinstance(item, list):
for value in item:
readings.append(value)
else:
readings.append(item)
return readings- Uniform flatten
[x for sub in items for x in sub]treats every entry as a bundle. It looks right on an all-bundle export like[[1, 2], [3, 4, 5]]and crashes the moment one bare reading shows up.- Per-entry check
- Branch on
isinstance(item, list): splice bundles, append readings. It gives the same output on the all-bundle case and is correct on every mixed one, including a run of bare integers.
Common follow-up questions
- What if bundles could contain other bundles to any depth? (Moving to a recursive or explicit-stack flatten and discussing depth limits.)
- How would you write this with `itertools.chain.from_iterable`, given the bare readings? (Whether they see that each scalar must be wrapped first, and whether that is clearer than the loop.)
- What if bundles could arrive as tuples as well as lists? (Broadening the check to `isinstance(item, (list, tuple))` without catching strings.)