Finding a key inside a nested dictionary with Python
Finding a key inside a nested dictionary with Python
Ditionary:
data =
"president":
"name": "Zaphod Beeblebrox",
"species": "Betelgeusian"
What I'd like to do is return if a key named "name" exists.
if 'president' in data and 'name' in data['president']:
print("found")
This works fine but only if I have pre knowledge of the dictionary's structure. Is there a way of knowing if there's a subkey called "name" recursively? I only found how to do this for the top level.
3 Answers
3
You can do a recursive search:
data =
"president":
"name": "Zaphod Beeblebrox",
"species": "Betelgeusian"
def r_find(target, key):
if key in target:
return True
else:
for k, v in target.items():
if isinstance(v, dict):
if r_find(v, key):
return True
return False
print(r_find(data, "name"))
print(r_find(data, "species"))
print(r_find(data, "no-name"))
Output
True
True
False
You can define a recursive generator with try
/ except
:
try
except
def recursive_keys(d):
for k, v in d.items():
try:
yield from recursive_keys(v)
except AttributeError:
yield k
'name' in set(recursive_keys(data)) # True
If you prefer, you can use isinstance
instead:
isinstance
def recursive_keys(d):
for k, v in d.items():
if isinstance(v, dict):
yield from recursive_keys(v)
else:
yield k
This is relatively expensive, since you are first creating a set
of all keys before checking if an item exists in the set
. As per @pault's comment, you can use:
set
set
any(x == 'name' for x in recursive_keys(data))
For a lazy solution without generators, see @DanielMesejo's solution. This may be more efficient since it avoids expensive __next__
calls.
__next__
How does the generator work here? Don't you need to build the whole set first to check the
in
condition? Wouldn't it be faster to return early as in @DanielMesejo's solution? Or maybe use any(x == 'name' for x in recursive_keys(data))
?– pault
Aug 24 at 19:44
in
any(x == 'name' for x in recursive_keys(data))
@pault, Yep, I realised this a moment ago and added a recursive function which returns
True
when it finds a match.– jpp
Aug 24 at 19:46
True
but what about using
any
with a generator (as in my edited original comment)? Won't that realize the speed up of the generator because of short-circuiting?– pault
Aug 24 at 19:47
any
@pault, Yes, good point. I think Daniel's solution would be faster (generator expressions can be slower), but yeh that's a good solution.
– jpp
Aug 24 at 19:53
A bit of a hacky non-traditional way would be to convert your dict
to a string using json.dumps
. Then you can search for the key as in the string.
dict
json.dumps
For example:
import json
def find_key(d, key):
if not isinstance(d, dict):
return False
else:
return '"'+key+'": ' in json.dumps(d)
print(find_key(data, 'name'))
#True
One limitation is that this won't work if you can have "name: "
inside one of your values.
"name: "
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
This is worth checking out : pypi.org/project/dictsearch
– Sreeram TP
Aug 24 at 19:29