# Round and Round They Go

> Each face waits its turn as the wheel comes back around.

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

Domain: Python · Difficulty: medium · Seniority: L4

## Problem

We're distributing a list of integer `values` (with duplicates) across a rotating set of `containers`, where each container is named 'set', 'list', or 'tuple'. Gather every occurrence of each distinct value into its own group ordered by value, then hand the groups out to the containers one at a time, wrapping back to the first container after the last. A 'set' container keeps only the unique values in sorted order; any other keeps the group exactly as gathered.

## Worked solution and explanation

### What this really is

Strip the costume and this is a two-phase group-then-dispatch: build a group per distinct value, walk the groups in a fixed order, and let a wrapping index over the container list decide each group's shape. The trap is order. If you emit groups in insertion or hash order instead of sorted-value order, every group lands in the wrong container, and if you forget that only 'set' deduplicates, your set groups keep the duplicates they were supposed to collapse. Both mistakes still run cleanly; they just produce a quietly wrong answer.

---

### Break down the requirements

#### Step 1: Build groups in sorted-key order

Walk `values` once and append each occurrence to `groups[v]`. Then iterate the keys in sorted order so the group sequence is deterministic.

#### Step 2: Rotate through containers by position

For group index `i`, the container is the one at the wrapping position over `containers`. This is the rotation; the wrap handles running past the end of the list.

#### Step 3: Apply the per-container transform

Only the 'set' container changes the values: deduplicate and sort ascending. For 'list' and 'tuple', leave the group's values in their gathered sequence. Wrap the result as {'values': [...], 'container': <name>}.

---

### The solution

**Group by value, rotate through containers, transform per container**

```python
def distribute(values: list[int], containers: list[str]) -> list[dict]:
    groups: dict[int, list[int]] = {}
    for v in values:
        groups.setdefault(v, []).append(v)
    out = []
    for i, key in enumerate(sorted(groups)):
        container = containers[i % len(containers)]
        group = groups[key]
        if container == 'set':
            shaped = sorted(set(group))
        else:
            shaped = list(group)
        out.append({'values': shaped, 'container': container})
    return out
```

> **Time and Space Complexity**
>
> **Time:** O(n + g log g) where n = len(values) and g is the number of distinct values (the sort is over distinct keys only).
> 
> **Space:** O(n) for the grouped values plus O(g) for the sorted-key iteration.

> **Interviewers Watch For**
>
> Strong candidates read the containers as plain strings ('set', 'list', 'tuple') and dispatch on the name, because that's exactly what the input shape hands them, not live set/list/tuple objects. They also reach for `setdefault` rather than an `if v not in groups` check so the group-building stays one line.

> **Common Pitfall**
>
> Forgetting that 'set' deduplicates. If group [3, 3] is assigned to a set position, the values list collapses to [3]. The other two containers preserve duplicates because the prompt asks for the gathered group sequence.

---

## Common follow-up questions

- What does the result look like when the number of distinct keys is less than the number of containers? Are the unused containers visible anywhere? _(Tests that unused containers are simply never assigned to.)_
- How would you add a fourth container type (say 'frozenset' or 'sorted_list') without re-touching the dispatcher? _(Tests extensibility via a strategy mapping rather than an inline if/elif chain.)_
- What if the values were dicts instead of integers? Which container would break first and how would you guard it? _(Tests awareness that unhashable types cannot be set elements, requiring a fallback.)_

## Related

- [All practice problems](https://datadriven.io/problems)
- [Mock interview mode](https://datadriven.io/interview/round_and_round_they_go)
- [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.