The Deep Selector

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
L4
Asked in
W. W. Grainger

Problem

A service hands back deeply nested JSON config, and downstream code needs only a handful of values from it, each named by a dot-separated path like user.name. Given data (the nested dict) and fields (the list of paths), return a dict mapping each path to the value found by walking that sequence of dict keys. A path maps to None when any segment along the way is missing or lands on something that is not a dict.

Tell it what you want. It knows where to look.

Example 1

Input:

data = {"user":{"age":30,"name":"Alice"},"address":{"city":"NY"}}, fields = ["user.name","address.city","user.email"]

Output:

{"user.name":"Alice","address.city":"NY","user.email":null}

Example 2

Input:

data = {"meta":{"id":"x1"},"order":{"items":{"count":3}}}, fields = ["order.items.count","meta.id","order.items.price"]

Output:

{"order.items.count":3,"meta.id":"x1","order.items.price":null}

Worked solution and explanation

What this really is

This is safe nested traversal wearing a JSON-extractor costume. The skill being probed: can you walk a variable-length key sequence into a structure of unknown depth without blowing up when the structure runs out before the path does? Splitting on dots and indexing is the easy 80 percent. The candidates who fail are the ones who assume every intermediate is a dict and write current[key] blindly. The first time a path reaches one level deeper than the data goes, say user.name.first where name is the string 'Bob', that line raises TypeError and takes the whole batch down with it.

Missing is normal, not exceptional

Notice the visible example asks for user.email, which simply is not there, and the expected answer is None, not a dropped key or an error. Partial resolution is the common case in config and API payloads, so the function must treat a missing or dead-ends-early path as a first-class, ordinary outcome. That reframes the whole problem: you are not looking up keys, you are attempting a walk that may fail at any step, and a failed walk yields None.


How to get there

Step 1: Split each path on dots

'order.items.count' becomes the segment sequence ['order', 'items', 'count']. Each segment is the next dict key to descend through.

Step 2: Attempt the walk, guarding each hop

Start at data and step inward one segment at a time. Before every step, confirm the thing in your hand is still a dict that actually holds the next key. The moment that check fails, stop: this path does not resolve.

Step 3: Record the outcome

If the walk consumed every segment, store the value you landed on. Otherwise store None. Either way the original dot-path stays the key.


The solution

Guarded dot-path navigation
def extract_json_fields(data: dict, fields: list[str]) -> dict:
    result = {}
    for path in fields:
        current = data
        resolved = True
        for key in path.split('.'):
            if isinstance(current, dict) and key in current:
                current = current[key]
            else:
                resolved = False
                break
        result[path] = current if resolved else None
    return result

The isinstance check is what lets a single-key path return a whole sub-dict and a too-deep path return None, both without raising.


Common follow-up questions