# The Map Reducer

> Map it. Reduce it. One answer.

Canonical URL: <https://datadriven.io/problems/the_map_reducer>

Domain: Python · Difficulty: medium · Seniority: L3

## Problem

Given a list of values, a mapper (single-arg function or lambda source string), and a reducer (two-arg function or lambda source string), apply mapper to each value, then reduce left-to-right with reducer. Return the final reduced value, or None if values is empty. If mapper or reducer is a string, eval it into a callable first.

## Worked solution and explanation

### Why this problem exists in real interviews

This tests understanding of the **map-reduce pattern**, a foundational pattern in distributed data processing. Interviewers check whether candidates can apply higher-order functions and handle the empty-list edge case cleanly.

---

### Break down the requirements

#### Step 1: Handle the empty case

If the input list is empty, return `None` immediately. There is nothing to map or reduce.

#### Step 2: Apply the mapper to every element

Transform each value using the mapper function, collecting results in a new list.

#### Step 3: Reduce left to right

Start with the first mapped value as the accumulator. Apply the reducer to the accumulator and each subsequent mapped value.

---

### The solution

**Manual map then left-fold reduce**

```python
def map_reduce(values, mapper, reducer):
    if not values:
        return None
    mapped = []
    for v in values:
        mapped.append(mapper(v))
    accumulator = mapped[0]
    for i in range(1, len(mapped)):
        accumulator = reducer(accumulator, mapped[i])
    return accumulator
```

> **Time and Space Complexity**
>
> **Time:** O(n) assuming both `mapper` and `reducer` are O(1) operations. One pass for mapping, one for reducing.
> 
> **Space:** O(n) for the intermediate mapped list. Could be O(1) if mapping and reducing were interleaved.

> **Interviewers Watch For**
>
> Do you separate the map and reduce phases clearly? While combining them saves memory, the two-phase approach mirrors real MapReduce frameworks and communicates intent more clearly.

> **Common Pitfall**
>
> Starting the reduce accumulator at 0 instead of `mapped[0]`. If the reducer is multiplication, starting at 0 would produce 0 for any input. The correct pattern initializes with the first element.

---

## Common follow-up questions

- How would you implement this lazily without materializing the mapped list? _(Tests generator-based approaches for memory efficiency.)_
- What if the list has exactly one element? _(Tests that the reduce loop is skipped and the single mapped value is returned.)_
- How does this relate to Python's built-in functools.reduce? _(Tests knowledge of the standard library equivalent.)_
- What if mapper or reducer could throw exceptions? _(Tests error handling strategy: fail fast or collect errors.)_

## Related

- [All practice problems](https://datadriven.io/problems)
- [Mock interview mode](https://datadriven.io/interview/the_map_reducer)
- [Python Interview Questions](https://datadriven.io/python-interview-questions)
- [Data Engineering Interview Prep Guide](https://datadriven.io/data-engineer-interview-prep)
- [Daily Challenge](https://datadriven.io/daily)

---

Source: DataDriven (https://datadriven.io). 100% free data engineering interview prep. Live code execution against Postgres 16, Python 3.11, and Spark sandboxes. No paywall, no premium tier, no signup gate.