简体   繁体   中英

Get key value from nested dict python

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"},
}

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()]

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']

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']

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())

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')]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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