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

时间:2020-10-12 16:37:28

标签: python list dictionary

所以我有一本字典

dict = {"key1" : {"key2": {"key3": 4 } } }

以及层次结构的键列表

list = ['key1","key2","abc"]

现在,我想检查键列表是否存在于保留该层次结构的字典中,如果不是,则返回None。 因此,在上述情况下,我应该返回None而不是Error

对于任何字典和该字典的键列表,解决方案必须是动态的,而不是涉及手动检查它的静态解决方案。 我已经研究了几个小时,但找不到解决方案,任何帮助将不胜感激

5 个答案:

答案 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