Check key existence in nested dictionaries
You could write a recursive function to check:
def f(d, keys):
if not keys:
return True
return keys[0] in d and f(d[keys[0]], keys[1:])
If the function returns True, the keys exist:
In [10]: f(test,"abcd")
Out[10]: True
In [11]: f(test,"abce")
Out[11]: False
If you want to test multiple key combinations:
for keys in ("abce","abcr","abcd"):
if f(test,keys):
print(keys)
break
abcd
To return the value it is pretty simple:
def f(d, keys):
if len(keys) == 1:
return d[keys[0]] if keys[0] in d else False
return keys[0] in d and f(d[keys[0]], keys[1:])
print(f(test,"abcd"))
e
You can test again for multiple key combinations:
def test_keys(keys):
for keys in keys:
val = f(test,keys)
if val:
return val
return False
print(test_keys(("abce","abcr","abc")))
You can also write the function iteratively:
def f(d, keys):
obj = object
for k in keys:
d = d.get(k, obj)
if d is obj:
return False
return d
print(f(test,"abcd"))
e
If you want to run a condition based on the return values:
def f(d, keys):
obj = object
for k in keys:
d = d.get(k, obj)
if d is obj:
return False
return d
from operator import mul
my_actions = {"c": mul(2, 2), "d": lambda: mul(3, 3), "e": lambda: mul(3, 3)}
for st in ("abce", "abcd", "abcf"):
val = f(test, st)
if val:
print(my_actions[val]())
9
Just test the key combo in the same order you would with your if/elif's etc..
It's not exactly what you want because it doesn't check existence, but here's a one-liner similar to the dict.get
method:
In [1]: test = {'a':{'b':{'c':{'d':'e'}}}}
In [2]: keys = 'abcd' # or ['a', 'b', 'c', 'd']
In [3]: reduce(lambda d, k: d.get(k) if d else None, keys, test)
Out[3]: 'e'
In [4]: keys = 'abcf'
In [5]: reduce(lambda d, k: d.get(k) if d else None, keys, test)
Unfortunately it's not very efficient because it doesn't stop as soon as one of the keys is missing.