Filter dictionaries and nested dictionaries for key

Question:

I want to solve the following problem without introducing several if/else if cases. I have the following dictionaries:

dict_1 = {"full_name": {"name": "Foo", "surname": "Bar"}, "age": 29, "test": 0}
dict_2 = {"name": "Foo", "age": 29, "test": 1}

Now, I want to receive the value of the key "name" for both dictionaries. In the "real" program situation, I don’t know if a structure of dict_1 or dict_2 will be present, but in all structures that will be present, the key "name" will exist. So I need a function like the following:

filter_dict_for_key(dict, key):
...
   return val(key)

For both dictionaries, I expect the output "Foo".
Is there an elegant pythonic way to do this with filter/dict comprehension, etc.?

Asked By: user44791

||

Answers:

A recursive function is usually the easiest way to handle an arbitrarily nested object. Since there’s always the possibility of there being more (or fewer) than one matching item, this function returns a list of matches:

>>> def get_name_nested(d):
...     """Return a list of all 'name' values in a nested dict."""
...     if not isinstance(d, dict):
...         return []
...     if 'name' in d:
...         return [d['name']]
...     return [n for s in d.values() for n in get_name_nested(s)]
...
>>> get_name_nested({"full_name": {"name": "Foo", "surname": "Bar"}, "age": 29, "test": 0})
['Foo']
>>> get_name_nested({"name": "Foo", "age": 29, "test": 1})
['Foo']

If you need to handle additional types of nesting (e.g. a list of dicts or a list of lists which may themselves be nested), it’s pretty straightforward to extend this approach to handle those.

Answered By: Samwise

You can use the default argument to dict.get()

name = mydict.get('name', mydict.get('full_name', {}).get('name'))

So if there’s no name key in the top-level, it looks in the full_name key. You have to use .get() for the default in case there’s no full_name key.

Or use a conditional expression:

name = mydict['name'] if 'name' in mydict else mydict['full_name']['name']

Note that this will get an error if neither key exists. You can use try/except to catch that if necessary.

Answered By: Barmar
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.