所以我有一本字典
dict = {"key1" : {"key2": {"key3": 4 } } }
以及层次结构的键列表
list = ['key1","key2","abc"]
现在,我想检查键列表是否存在于保留该层次结构的字典中,如果不是,则返回None。 因此,在上述情况下,我应该返回None而不是Error
对于任何字典和该字典的键列表,解决方案必须是动态的,而不是涉及手动检查它的静态解决方案。 我已经研究了几个小时,但找不到解决方案,任何帮助将不胜感激
答案 0 :(得分:2)
我认为这个小的递归函数应该可以做到。
def find_path(nested_structure, path):
top = path[0]
if top not in nested_structure.keys():
return None
else:
value = nested_structure[top]
if isinstance(value, dict) and len(path)>0:
return find_path(nested_structure[top], path[1:])
else:
return value
structure = {"key1" : {"key2": {"key3": 4 }, "key2b": 42 } }
print(find_path(structure, ["key1","key2","abc"])) # -> None
print(find_path(structure, ["key1","key2","key3"])) # -> 4
答案 1 :(得分:1)
您可以为此使用functools.reduce()
,您只需要预料KeyError
。例如:
from functools import reduce
d = {"key1" : {"key2": {"key3": 4 } } }
def findindict(d, l):
try:
return reduce(lambda current_dict, key: current_dict[key], l, d)
except (KeyError, TypeError):
return None
findindict(d, ["key1","key2", "key3"])
# 4
findindict(d, ["key1","key2", "abc"])
# None
findindict(d, ["key1","key2", "key3", "key6"])
#None
答案 2 :(得分:1)
不要将dict和list用作变量名。如果要从给定的键返回结构:
def NextedKeyExists(dictobj, key):
if key in dictobj:
return dictobj[key]
for v in dictobj.values():
if isinstance(v, dict):
r = NextedKeyExists(v, key)
if r != None:
return r
return None
用法:
dictobj = {"key1" : {"key2": {"key3": 4 } } }
listobj = ["key1", "key2", "abc"]
for l in listobj:
print (l, " -> ", NextedKeyExists(dictobj, l))
输出:
key1 -> {'key2': {'key3': 4}}
key2 -> {'key3': 4}
abc -> None
答案 3 :(得分:0)
您可以这样尝试,不要使用dict作为变量名:
mydict = {"key1" : {"key2": {"key3": 4 } } }
mykeys = []
def walk_dict(d,depth=0):
for k,v in sorted(d.items(),key=lambda x: x[0]):
if isinstance(v, dict):
mykeys.append(k)
walk_dict(v,depth+1)
else:
mykeys.append(k)
def rec_check_keys(keylist):
thekeys = walk_dict(mydict)
flag = True
for x in keylist:
if not x in thekeys:
flag = False
if flag == False:
return None
else:
return True
答案 4 :(得分:-1)
Mark Meyer的答案被选为正确的答案,但对于以下输入将失败:
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
捕获该TypeError将无济于事-它不会遍历嵌套字典中的所有键。
失败,因为它不会检查所有键。因此,让我们创建一个函数,它将获取所有键:
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
因此您的目标函数将如下所示:
def all_keys_presented_in_dict(d, keys):
return not bool(set(keys) - set(get_all_keys(d)))
如果稍后您希望检查目标词典中是否至少显示了某些(不是全部)键-您可以轻松地做到这一点,因为您可以访问嵌套词典中的所有键。
更新
正如@MarkMeyer所注意到的-OP询问了键的“存在”和“层次结构的保留”。因此,应更新我的解决方案,以检查一个(目标键)列表是否是另一个(所有键,保留层次结构)列表的子序列。
因此,我们添加该功能来检查以下内容:
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))
例如:
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