简体   繁体   English

如何在Python中的嵌套字典中检查值?

[英]How do I check value in a nested dictionary in Python?

Suppose we have a list of dictionaries listD where each dictionary is quite deeply nested with more dictionaries. 假设我们有一个字典listD的列表,其中每个字典都嵌套了很多字典。 egsuppose that the first element of listD is: 例如,假设listD的第一个元素是:

listD[0] = {"bar1":{"bar2":{"bar3":1234}}}

Now I want to check if listD[i]["bar1"]["bar2"]["bar3"] == 1234 for all i. 现在,我要检查listD [i] [“ bar1”] [“ bar2”] [“ bar3”] == 1234是否适用于所有i。 For the first element where i = 0, this is easy as we can just use the expression: 对于i = 0的第一个元素,这很容易,因为我们可以使用以下表达式:

listD[0]["bar1"]["bar2"]["bar3"] == 1234 

But I cannot simply write a loop like: 但是我不能简单地写一个像这样的循环:

for dictelem in listD:
  if dictelem["bar1"]["bar2"]["bar3"] == 1234:
    print "equals 1234"

This is because some of the dictionary elements of listD might be of the form 这是因为listD的某些字典元素可能具有以下形式:

listD[i] = {"bar1":{"bar2":"abcd"}} or
listD[i] = {"bar1":{"bar2":None}} 

and if I try to access "bar3" when it doesn't exists, an error will be raised. 如果我尝试访问不存在的“ bar3”,则会出现错误。

Right now I am manually specifying in the code to check for the existence of the bar1, bar2 and bar3 keys and whether that are in fact dictionaries or not. 现在,我在代码中手动指定要检查bar1,bar2和bar3键的存在以及它们是否实际上是字典。 But this is really verbose and I'm quite sure there's a simpler way to do it but I can't figure out how. 但这确实很冗长,我很确定有一种简单的方法可以做到,但是我不知道怎么做。

def dictcheck(d, p, v):
    if len(p):
        if isinstance(d,dict) and p[0] in d:
            return dictcheck(d[p[0]], p[1:], v)
    else:
        return d == v

You pass one dict d , one path of keys p , and the final value to check v . 您传递一个dict d ,一个键p路径以及最终值以检查v It will recursively go in the dicts and finally check if the last value is equal to v . 它将递归地输入字典,最后检查最后一个值是否等于v

>>> dictcheck({"bar1":{"bar2":{"bar3":1234}}}, ('bar1','bar2','bar3'), 1234)
True

>>> dictcheck({"bar1":1234}, ('bar1','bar2','bar3'), 1234)
False

So, to answer your question ( I want to check if listD[i]["bar1"]["bar2"]["bar3"] == 1234 for all i ): 因此,回答您的问题( 我想检查listD [i] [“ bar1”] [“ bar2”] [“ bar3”] == 1234是否代表所有i ):

all(dictcheck(x, ('bar1','bar2','bar3'), 1234) for x in listD)

just use a try/except block this way: 只是这样使用try/except块:

for dictelem in listD:
    try:
        if dictelem["bar1"]["bar2"]["bar3"] == 1234:
            print "equals 1234"
    except TypeError:
        pass

When dealing with nested dictionaries, I think of them as a tree where the keys make up the path to the value. 在处理嵌套字典时,我将它们视为一棵树,其中的键构成了通往值的路径。 With that in mind, I created a non-recursive function, dict_path with takes in a nested dictionary, the key path, and a value in case not found: 考虑到这一点,我创建了一个非递归函数dict_pathdict_path带有一个嵌套字典,键路径和一个值(如果找不到):

def dict_path(dic, path, value_if_not_found=None):
    path = path.split('.')
    try:
        for key in path:
            dic = dic[key]
        return dic
    except (KeyError, TypeError):
        return value_if_not_found

listD = [
    {"bar1": {"bar2": 'abcd'}},
    {"bar1": {"bar2": None}},
    {"bar1": {"bar2": {"bar3": 1234}}},
]

for dic in listD:
    value = dict_path(dic, 'bar1.bar2.bar3')
    if value == 1234:
        print 'Equals 1234:', dic

The function keeps traversing the nested dictionary until one of these three conditions occur: 该函数将继续遍历嵌套字典,直到出现以下三种情况之一:

  1. It found the value in question. 它发现了有问题的价值。 In this case, return that value 在这种情况下,返回该值
  2. Along the way, the object is a dictionary, but does not have the requested key. 在此过程中,对象是字典,但没有请求的键。 In this case, a KeyError is raised 在这种情况下,会引发KeyError
  3. The object is not a dictionary, the TypeError is raised 该对象不是字典, TypeError

For case 2 and 3, we simply return value_if_not_found 对于情况2和3,我们只返回value_if_not_found

you can try this 你可以试试这个

for item in listD:
    if item.get("bar1",{}).get("bar2",{}).get("bar3","") == 1234:
        print "yeah, gotcha"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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