简体   繁体   中英

Get a list of all keys in nested dictionary

I want to get a list of all keys in a nested dictionary that contains lists and dictionaries.

keys_list = []
def get_keys(d_or_l, keys_list):
    if isinstance(d_or_l, dict):
        for k, v in iter(sorted(d_or_l.iteritems())):
            if isinstance(v, list):
                get_keys(v, keys_list)
            elif isinstance(v, dict):
                get_keys(v, keys_list)
            else:
                keys_list.append(k)
    elif isinstance(d_or_l, list):
        for i in d_or_l:
            if isinstance(i, list):
                get_keys(i, keys_list)
            elif isinstance(i, dict):
                get_keys(i, keys_list)
    else:
        print "** Skipping item of type: {}".format(type(d_or_l))
    return keys_list

This should do the job:

def get_keys(dl, keys_list):
    if isinstance(dl, dict):
        keys_list += dl.keys()
        map(lambda x: get_keys(x, keys_list), dl.values())
    elif isinstance(dl, list):
        map(lambda x: get_keys(x, keys_list), dl)

To avoid duplicates you can use set, eg:

keys_list = list( set( keys_list ) )

Example test case:

keys_list = []
d = {1: 2, 3: 4, 5: [{7: {9: 1}}]}
get_keys(d, keys_list)
print keys_list
>>>> [1, 3, 5, 7, 9]

As it stands, your code ignores keys that lead to list or dict values. Remove the else block in your first for loop, you want to add the key no matter what the value is.

keys_list = []
def get_keys(d_or_l, keys_list):
    if isinstance(d_or_l, dict):
        for k, v in iter(sorted(d_or_l.iteritems())):
            if isinstance(v, list):
                get_keys(v, keys_list)
            elif isinstance(v, dict):
                get_keys(v, keys_list)
            keys_list.append(k)   #  Altered line
    elif isinstance(d_or_l, list):
        for i in d_or_l:
            if isinstance(i, list):
                get_keys(i, keys_list)
            elif isinstance(i, dict):
                get_keys(i, keys_list)
    else:
        print "** Skipping item of type: {}".format(type(d_or_l))
    return keys_list

get_keys({1: 2, 3: 4, 5: [{7: {9: 1}}]}, keys_list) returns [1, 3, 9, 7, 5]

To avoid duplication, you could use a set datatype instead of a list .

Updating @MackM's response to Python 3 as dict.iteritems has been deprecated (and I prefer to use f-strings over the .format{} styling):

keys_list = []
def get_keys(d_or_l, keys_list):
    if isinstance(d_or_l, dict):
        for k, v in iter(sorted(d_or_l.items())):  #  Altered line to update deprecated method
            if isinstance(v, list):
                get_keys(v, keys_list)
            elif isinstance(v, dict):
                get_keys(v, keys_list)
            keys_list.append(k)   
    elif isinstance(d_or_l, list):
        for i in d_or_l:
            if isinstance(i, list):
                get_keys(i, keys_list)
            elif isinstance(i, dict):
                get_keys(i, keys_list)
    else:
        print(f'** Skipping item of type: {type(d_or_l)}')  #  Altered line to use f-strings
    return keys_list


unique_keys = list(set(get_keys(my_json_dict, keys_list)))  # Added line as example use case

Here is a simple solution:

def get_nested_keys(d, keys):
    for k, v in d.items():
        if isinstance(v, dict):
            get_nested_keys(v, keys)
        else:
            keys.append(k)

keys_list = []
get_nested_keys(test_listing, keys_list)
print(keys_list)

If you want to know the hierarchy of the keys as well, you can modify the function like so:

def get_nested_keys(d, keys, prefix):
    for k, v in d.items():
        if isinstance(v, dict):
            get_nested_keys(v, keys, f'{prefix}:{k}')
        else:
            keys.append(f'{prefix}:{k}')

I would extend @pm007 answer by a python 2 & 3 friendly version:

def get_keys(dl, keys=None):
    keys = keys or []
    if isinstance(dl, dict):
        keys += dl.keys()
        list(map(lambda x: get_keys(x, keys), dl.values()))
    elif isinstance(dl, list):
        list(map(lambda x: get_keys(x, keys), dl))
    return list(set(keys))
d = {1: 2, 3: 4, 5: {7: {1: 1}}}
get_keys(d)

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