0

What is the best way to index a deeply nested dictionary? Consider the following example:

x = {'a': {'b': {'c': {'d': 1}}}}
item = x['a']['b']['c']['d']

Is there a convenient way to provide a path maybe?

# something like this
item = x.get_path('a/b/c/d')
Ali
  • 328
  • 2
  • 7
  • 1
    [Xpath like query for nested python dictionaries](https://stackoverflow.com/q/7320319) Pretty old question, though. Sort the answers by date. – 001 Nov 27 '21 at 15:26
  • Perfect! That works very nicely. – Ali Nov 27 '21 at 15:33
  • accept the answer if it fulfill your requirements. – Samsul Islam Nov 27 '21 at 15:37
  • Ali: Sorry to post answer and then delete it - I realised after posting recursive implementation that it could be done with a simple loop - now edited and undeleted. – alani Nov 27 '21 at 15:47
  • Note: neither of the answers posted so far support the exact lookup syntax in the question. To do that, you would have to subclass `dict` to add such a lookup method - probably more trouble than it's worth, but possible in principle. – alani Nov 27 '21 at 15:52
  • The accepted answer can be amended to accept the lookup syntax `nested_get('a/b/c/d').split('/'), x)`. – Ali Nov 27 '21 at 16:00

2 Answers2

5

You can build a simple approach, using the built-in library, as below:

from functools import reduce, partial
from operator import getitem

nested_get = partial(reduce, getitem)


x = {'a': {'b': {'c': {'d': 1}}}}

item = nested_get(["a", "b", "c", "d"], x)
print(item)

Output

1

UPDATE

To emulate the behavior of dict.get, use:

def nested_get(path, d, default=None):
    current = d
    for key in path:
        try:
            current = current[key]
        except KeyError:
            return default
    return current


x = {'a': {'b': {'c': {'d': 1}}}}

item = nested_get(["a", "b", "c", "d"], x)
print(item)
item = nested_get(["a", "b", "e", "d"], x)
print(item)

Output

1
None
Dani Mesejo
  • 61,499
  • 6
  • 49
  • 76
  • Very nice. Is there a way to provide a None value if the path doesn't exit? A bit like the .get method. – Ali Nov 27 '21 at 15:37
  • 1
    The updated answer provides a solution to my comment above. Thanks Dani. – Ali Nov 27 '21 at 15:57
2

Here is a simple implementation that supports approximately the lookup syntax that you are looking for.

def get_value(x, path):
    for key in path.split('/'):
        x = x[key]
    return x

x = {'a': {'b': {'c': {'d': 1}}}}

print(get_value(x, 'a/b/c/d'))

gives:

1

If any of the keys do not exist, then you will get an KeyError. If you want some other behaviour (e.g. return None) then you could change the x = x[key] line to:

        try:
            x = x[key]
        except KeyError:
            return None
alani
  • 12,573
  • 2
  • 13
  • 23