繁体   English   中英

根据列表检查嵌套字典python中是否存在键

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM