# The Onion Layer

> Peel from the outside in - one ring at a time.

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

Domain: Python · Difficulty: hard · Seniority: L5

## Problem

Given an m x n 2D matrix, return a flat list of all elements in spiral order starting from the top-left corner and moving clockwise.

## Worked solution and explanation

### Why this problem exists in real interviews

This tests **boundary management and directional traversal** on a 2D grid. Spiral order requires tracking four shrinking boundaries and switching directions at each turn, revealing whether candidates can manage complex state transitions cleanly.

> **Trick to Solving**
>
> Maintain four boundaries: top, bottom, left, right. Traverse the current ring in four directions (right, down, left, up), then shrink the corresponding boundary inward. Repeat until all boundaries cross.

---

### Break down the requirements

#### Step 1: Initialize four boundaries

Top row, bottom row, left column, right column. These define the current outermost unvisited ring.

#### Step 2: Traverse right across the top row

Collect elements from left to right along the top boundary, then increment top.

#### Step 3: Traverse down the right column

Collect elements from top to bottom along the right boundary, then decrement right.

#### Step 4: Traverse left across the bottom row

If top has not crossed bottom, collect elements from right to left along the bottom boundary, then decrement bottom.

#### Step 5: Traverse up the left column

If left has not crossed right, collect elements from bottom to top along the left boundary, then increment left.

#### Step 6: Repeat until boundaries cross

The loop ends when `top > bottom` or `left > right`.

---

### The solution

**Four-boundary spiral with direction cycling**

```python
def spiral_order(matrix):
    if not matrix:
        return []
    result = []
    top = 0
    bottom = len(matrix) - 1
    left = 0
    right = len(matrix[0]) - 1
    while top <= bottom and left <= right:
        for col in range(left, right + 1):
            result.append(matrix[top][col])
        top += 1
        for row in range(top, bottom + 1):
            result.append(matrix[row][right])
        right -= 1
        if top <= bottom:
            for col in range(right, left - 1, -1):
                result.append(matrix[bottom][col])
            bottom -= 1
        if left <= right:
            for row in range(bottom, top - 1, -1):
                result.append(matrix[row][left])
            left += 1
    return result
```

> **Time and Space Complexity**
>
> **Time:** O(m * n) where m and n are the matrix dimensions. Every element is visited exactly once.
> 
> **Space:** O(1) beyond the output list.

> **Interviewers Watch For**
>
> Do you guard the bottom-row and left-column traversals with boundary checks? Without `if top <= bottom` and `if left <= right`, single-row or single-column matrices produce duplicate elements.

> **Common Pitfall**
>
> Forgetting the guards for the reverse traversals. This causes bugs on non-square matrices where one dimension is exhausted before the other.

---

## Common follow-up questions

- How would you fill a matrix in spiral order instead of reading it? _(Tests reversing the logic: assign values while traversing boundaries.)_
- What if the matrix were very large and you needed to access specific positions? _(Tests computing the spiral index mathematically without full traversal.)_
- How would you generalize to counter-clockwise spiral order? _(Tests reordering the four direction passes.)_
- What if the matrix had holes (None values) that should be skipped? _(Tests adding a filter condition during traversal.)_

## Related

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