Search code examples
pythondictionarynestedkey

Iterate over nested keys in Python dict and break on first occurence


I have a JSON dict like the following :

             "{
                        "a":1,
                        "b":{
                             "b1":False,
                             "b2":{"b21": 2, "b22":8}
                         },  
                        "c": { 
                            "b1":True, 
                            "b2":2,
                            "b4":8
                         },
                        "d":{
                            "b1":False, 
                            "d1":89
                         }
                       }"

I want to check the value of the key "b1" in the dictionary, and get out when I find b1=True. If I check the entire dict (nested keys included), and I don't find b1=True, then I would like to return False. For the example above, my function should return True.

Basically I want to break the code on the first occurrence of b1=True and iterate over all the keys of the dict (in all levels), and if this occurrence does not exist, return False.

This is what I came up with :

def isb1True(jsonDoc):
  found = False
    for (key,value) in jsonDoc.iteritems():
        if key=='b1':
            if value==True :
                found=True
                break
        else:
            isb1True(value)
   return found

My code always returns False.


Solution

  • You need to return from the recursive calls too, and use that to inform wether or not you are going to continue looping; your code ignores what the recursive isb1True(value) call returns.

    You can use the any() function to short-circuit testing recursive values:

    def isb1true(d):
        if not isinstance(d, dict): return False
        return any(v if k == 'b1' else isb1true(v) for k, v in d.iteritems())
    

    The above recurses for any key that is not 'b1', and recursion stops when that value is not a dictionary (in which case it won't be b1 so that result is not a 'b1': True case).

    I'm assuming that 'b1' is always set to a boolean; the above returns True for any 'truthy' value for that key.

    Some test cases:

    >>> isb1true({'b1': True})
    True
    >>> isb1true({'b1': False})
    False
    >>> isb1true({'b': {'b1': True}})
    True
    >>> isb1true({'b': {'b1': False}})
    False
    >>> isb1true({'b': {'c': True, 'spam': 'eggs', 'ham': {'bar': 'baz', 'b1': True}}})
    True
    >>> isb1true({'b': {'c': True, 'spam': 'eggs', 'ham': {'bar': 'baz'}}})
    False