Answer of Mark Meyer was selected as the right one, but it will fail for the following input:
d = {"key1" : {"key2": {"key3": 4 } }, "key5": {"key6": 1}}
findindict(d, ["key1","key2", "key3", "key6"])
In [86]: def findindict(d, l):
...: try:
...: return reduce(lambda current_dict, key: current_dict[key], l, d)
...: except KeyError:
...: return None
...:
In [87]: d = {"key1" : {"key2": {"key3": 4 } }, "key5": {"key6": 1}}
In [88]: findindict(d, ["key1","key2", "key3", "key6"])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-88-42fa73bf849f> in <module>
----> 1 findindict(d, ["key1","key2", "key3", "key6"])
<ipython-input-86-c54e471e6146> in findindict(d, l)
1 def findindict(d, l):
2 try:
----> 3 return reduce(lambda current_dict, key: current_dict[key], l, d)
4 except KeyError:
5 return None
<ipython-input-86-c54e471e6146> in <lambda>(current_dict, key)
1 def findindict(d, l):
2 try:
----> 3 return reduce(lambda current_dict, key: current_dict[key], l, d)
4 except KeyError:
5 return None
TypeError: 'int' object is not subscriptable
Catching of that TypeError will not help - it will not traverse all the keys inside nested dict.
It's failing because it will not check all the keys. So let's create the function, which will get all the keys:
def get_all_keys(d):
dict_keys = list(d.keys()) if isinstance(d, dict) else []
keys = dict_keys[:]
for key in dict_keys:
keys += get_all_keys(d[key])
return keys
So your target function will look like:
def all_keys_presented_in_dict(d, keys):
return not bool(set(keys) - set(get_all_keys(d)))
If later you would love to check if at least some (not all) of the keys are presented in target dictionary - you can easily do that, because you have access to all keys in the nested dictionary.
UPDATE
As @MarkMeyer has noticed - OP has asked about "existence" of keys and "retaining of hierarchy". So my solution should be updated to check if one list (of target keys) is subsequence of another list (of all keys, retaining hierarchy).
So let's add the function to check that:
def is_subsequence(subsequence, target):
subsequence_length = len(subsequence)
for i in range(len(target) - subsequence_length + 1):
if target[i:i + subsequence_length] == subsequence:
return True
return False
def all_keys_presented_in_dict_with_hierarchy_being_retained(d, keys):
return is_subsequence(keys, get_all_keys(d))
For example:
In [26]: all_keys_presented_in_dict_with_hierarchy_being_retained(d, ["key2", "key3"])
Out[26]: True
In [27]: all_keys_presented_in_dict_with_hierarchy_being_retained(d, ["key2"])
Out[27]: True
In [28]: all_keys_presented_in_dict_with_hierarchy_being_retained(d, ["key2", "key1"])
Out[28]: False