Reputation: 2384
I have class with a nested dictionary data object. I need to get all the key values from it. What's the best efficient way to do this?
I'm stuck with following:
for k,v in data.items():
print v.keys()
This is the data:
data = {
"BANK": {
"no_data": "INT",
},
"SHOCK": {
"drop": "NOTI",
"rise": "NOTI",
"high_risk": "ALERT",
},
"OFFLINE": {"online": None, "offline_few": "ALERT"},
}
Upvotes: 3
Views: 1295
Reputation: 1459
You could use a NestedDict
. First install ndicts
pip install ndicts
Then
from ndicts.ndicts import NestedDict
data = {
"BANK": {
"no_data": "INT",
},
"SHOCK": {
"drop": "NOTI",
"rise": "NOTI",
"high_risk": "ALERT",
},
"OFFLINE": {"online": None, "offline_few": "ALERT"},
}
nd = NestedDict(data)
The result
>>> list(nd.keys())
[('BANK', 'no_data'), ('SHOCK', 'drop'), ('SHOCK', 'rise'), ('SHOCK', 'high_risk'), ('OFFLINE', 'online'), ('OFFLINE', 'offline_few')]
Upvotes: 0
Reputation: 26886
Using a generator:
def all_keys(d):
for k, v in d.items():
yield k
# assume that anything with `items` property will be a mapping
# this can be replaced with: `isinstance(v, dict)` or `isinstance(v, collections.Mapping)`
if hasattr(v, 'items'):
yield from all_keys(v)
On your input this produces:
data = {
"BANK": {
"no_data": "INT",
},
"SHOCK": {
"drop": "NOTI",
"rise": "NOTI",
"high_risk": "ALERT",
},
"OFFLINE": {"online": None, "offline_few": "ALERT"},
}
print(list(all_keys(data)))
# ['BANK', 'no_data', 'SHOCK', 'drop', 'rise', 'high_risk', 'OFFLINE', 'online', 'offline_few']
Upvotes: 1
Reputation: 17156
Recursive Function
Gets all keys at all levels of nested dictionary
def get_keys(d, result = None):
# use default of None to fix issue noted by @Ch3steR
# namely: http://effbot.org/zone/default-values.htm
if result is None:
result = []
for k, v in d.items():
if isinstance(v, dict):
result.append(k)
get_keys(v, result)
else:
result.append(k)
return result
Test
print(get_keys(data))
Output
['BANK', 'no_data', 'SHOCK', 'drop', 'rise', 'high_risk', 'OFFLINE', 'online', 'offline_few']
Upvotes: 0
Reputation: 2962
If all your "actual" key-value pairs are at a certain depth, for example for depth 1, you can go like:
data = {
"BANK": {
"no_data": "INT",
},
"SHOCK": {
"drop": "NOTI",
"rise": "NOTI",
"high_risk": "ALERT",
},
"OFFLINE": {"online": None, "offline_few": "ALERT"},
}
dic = {k:v for val in data.values() for k,v in val.items()}
But if you dont know that:
data = {
"BANK": {
"no_data": "INT",
},
"SHOCK": {
"drop": "NOTI",
"rise": "NOTI",
"high_risk": "ALERT",
},
"online": None,
"offline_few": "ALERT"
}
In this case you need to use recursion:
def unnest(dic, final=dict()):
for key, val in dic.items():
if not isinstance(val, dict):
final[key] = val
else:
dic2 = dict()
for k, v in val.items():
dic2[k] = v
unnest(dic2, final)
return final
dic = unnest(data, {}) #every use of the function should have {} to solve issue pointed by @Ch3steR
In any case, once you have the "un-nested" dictionary it is trivial to print out the keys:
print(dic.keys())
Upvotes: 0
Reputation: 64308
An elegant way to concatenate lists (your value.keys()
lists) into one is using a double-loop list comprehenstion, like this:
nested_keys = [
key
for val in data.values()
for key in val.keys()]
Upvotes: 3