Samiella Samiella - 4 months ago 16
Python Question

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
.

Answer

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