Home > Software engineering >  Getting keys from nested dictionary without using for loops
Getting keys from nested dictionary without using for loops

Time:10-20

My Problem: I have a nested dictionary that looks like this:

my_dict = {
    'type_1' : {
        'id1' : some_item,
        'id2' : some_item_2,
    },
    'type_2' :{
        'id3' : some_item3,
        'id4' : some_item4,
    }
}

I don't intent to add more nesting in those sub_dicts, so I think this should be fairly easy.

Now I want to get all to get all inner keys (everything that starts with 'id') in one list,
so that i get ['id1', 'id2', 'id3', 'id4]

The easy way would be to use two for loops, but I want it to be as concise as humanly possible.

My initial approach looks like this:
all_keys = [list(sub_dict.keys()) for sub_dict in my_dict.values()] which outputs
[['id1', 'id2'], ['id3', 'id4']] which is halfway to where I want to get. Adding an asterisk in front of list(sub_dict(keys)) raises a syntax error:
"iterable unpacking cannot be used in comprehension"

Any idea how I get all 'id'-strings in one unnested list with max one additional line of code?

CodePudding user response:

You need to un-ravel the keys of the nested dictionaries, as below:

res = [key for d in my_dict.values() for key in d.keys() if isinstance(key, str) and key.startswith("id")]
print(res)

Output

['id1', 'id2', 'id3', 'id4']

Additionally you need to check that the keys are actually strings (using isinstance) and then check if they start with "id" (using startswith).

As an alternative use chain.from_iterable:

res = [key for key in chain.from_iterable(my_dict.values()) if isinstance(key, str) and key.startswith("id")]
print(res)

Also as suggested by @user2390182 you don't need to use .keys() on the nested dictionaries, just do:

res = [key for sub_dict in my_dict.values() for key in sub_dict if isinstance(key, str) and key.startswith("id")]

CodePudding user response:

You solution is OK and you can correct this with itertools.chain like below:

>>> from itertools import chain
>>> list(chain.from_iterable(sub_dict for sub_dict in my_dict.values()))
['id1', 'id2', 'id3', 'id4']

By thanks @user2390182 shorted approach:

>>> list(chain.from_iterable(my_dict.values()))
# Or
>>> [*chain(*map(chain, my_dict.values()))]
['id1', 'id2', 'id3', 'id4']

CodePudding user response:

Firstly you need to access to values of the dict then the keys of that value

new_dict=[id for i in my_dict.values() for id in i.keys()]
  • Related