nested list
recursion
programming
algorithms
data handling

How to run function on the deepest level only in a nested list?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If you want to apply a function only to the deepest level of a nested list, you first need to define what "deepest" means. In most cases, it means elements that appear at the maximum nesting depth, not every non-list leaf you encounter during recursion.

The Two-Step Approach

For uneven nested lists, the cleanest solution has two phases:

  1. compute the maximum depth of the structure
  2. walk the structure again and apply the function only at that depth

That is more reliable than trying to guess during a single pass, because you do not yet know whether a current leaf is truly deepest until you have seen the entire structure.

Example Input

Suppose the data is:

python
data = [1, [2, 3], [[4, 5], 6], [[[7]]]]

The deepest scalar element is 7, because it appears at a greater nesting level than the other values.

If the goal is to double only the deepest-level items, the result should become:

python
[1, [2, 3], [[4, 5], 6], [[[14]]]]

Step 1: Find The Maximum Depth

Here is a function that computes the maximum depth of a nested list structure.

python
1def max_depth(value):
2    if not isinstance(value, list):
3        return 0
4    if not value:
5        return 1
6    return 1 + max(max_depth(item) for item in value)
7
8
9print(max_depth([1, [2, 3], [[4, 5], 6], [[[7]]]]))

This treats non-list values as depth 0, then adds one for each list layer.

Step 2: Apply The Function Only At That Depth

Now use the computed depth to transform only items at the deepest level.

python
1def apply_at_deepest(value, func, current_depth, target_depth):
2    if not isinstance(value, list):
3        if current_depth == target_depth:
4            return func(value)
5        return value
6
7    return [
8        apply_at_deepest(item, func, current_depth + 1, target_depth)
9        for item in value
10    ]
11
12
13def map_deepest(data, func):
14    target_depth = max_depth(data)
15    return apply_at_deepest(data, func, 0, target_depth)
16
17
18result = map_deepest([1, [2, 3], [[4, 5], 6], [[[7]]]], lambda x: x * 2)
19print(result)

This keeps the original structure intact and modifies only the scalar values located at the maximum depth.

What Happens With Several Deepest Branches

If multiple branches share the same maximum depth, the function is applied to all scalar values at that depth.

python
data = [[1, [2]], [[3], 4], [[[5]], [[6]]]]
print(map_deepest(data, lambda x: x + 100))

That behavior is usually what people mean by "deepest level only": every value that lives on the deepest level, not just the first one found.

Single-Pass Alternatives

You can solve this with a more complex single-pass recursion that returns both transformed data and depth information together. That approach can be elegant, but it is harder to read and reason about.

For most production code, the two-pass approach is better because:

  • it is easier to test
  • the recursion is simpler
  • the intent is obvious

Unless the nested structure is enormous and performance is extremely tight, clarity is the better tradeoff.

Decide Whether Empty Lists Matter

An empty list introduces a design choice. Does an empty sublist count as deeper structure even if it contains no values to transform?

The implementation above counts list layers structurally, but only scalar values can actually be transformed. That is usually fine, but if your domain treats empty lists specially, document the rule clearly.

Common Pitfalls

A common mistake is applying the function to every non-list leaf. That solves a different problem: mapping over all leaf values rather than only the deepest ones.

Another issue is assuming all branches have the same depth. Many nested-list bugs appear only when the structure is uneven.

Be careful about mutability as well. If you modify the list in place during recursion, it becomes easier to introduce hard-to-debug side effects. Returning a new structure is usually safer.

Finally, define what counts as a nested list up front. The examples here treat only Python list objects as structural containers. If tuples or other iterables should also count, adjust the type checks deliberately.

Summary

  • To apply a function only at the deepest level, first determine the maximum nesting depth.
  • A two-pass solution is usually simpler and safer than a clever one-pass recursion.
  • Transform only values whose current depth matches the maximum depth.
  • Uneven branches are where this problem becomes interesting, so test them explicitly.
  • Be clear about how your code treats empty lists and non-list container types.

Course illustration
Course illustration

All Rights Reserved.