[英]Check if a key exists in a nested dictionary python based on a list
所以我有一本字典
dict = {"key1" : {"key2": {"key3": 4 } } }
和层次结构的键列表
list = ['key1","key2","abc"]
现在我想检查键列表是否存在于保留该层次结构的字典中,如果不存在,则可能返回一个 None。 所以在上面的例子中我应该返回一个 None 而不是一个错误
对于任何字典和该字典的键列表,解决方案必须是动态的,而不是涉及手动检查的静态解决方案。 我已经研究了几个小时,但找不到解决方案,任何帮助将不胜感激
我认为这个小递归函数应该可以做到。
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
您可以为此使用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
不要使用 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
您可以尝试这样不要使用 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
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 将无济于事 - 它不会遍历嵌套 dict 中的所有键。
它失败了,因为它不会检查所有的键。 所以让我们创建函数,它将获得所有的键:
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.