Nested dictionary comprehension (2 level)

Viewed 179

I have a list of dictionary objects

data = [
    {
        'id': 1,
        'parent_id': 101 ,
        'name': 'A'        
    },
    {
        'id': 2,
        'parent_id': 101,
        'name': 'B'        
    },
    {
        'id': 3,
        'parent_id': 102,
        'name': 'C'        
    },
    {
        'id': 4,
        'parent_id': 102,
        'name': 'D'        
    }
]

I want to convert this to a nested dictionary.

Structure:

{
    parent_id_value: {
        name_value: id_value
    }
}

Result of the sample list of dictionary object should be like this

{
    101: {
        'A': 1,
        'B': 2
    },
    102: {
        'C': 3,
        'D': 4
    }
}

I know we can run a for loop and use setdefault to set/get paren_id value and then add the name and id as key, value

new_dic = {}
for i in data:
    new_dic.setdefault(i['parent_id'], {})[i['name']] = i['id']
print(new_dic)

But I am looking for a more pythonic way, meaning is it possible through dictionary comprehension?

2 Answers

First, sort the list using operator.itemgetter to supply the key:

data.sort(key=itemgetter('parent_id'))

Then use itertools.groupby to group the intended sections in a nested dict-comprehension:

data = {
    key: {item['name']: item['id'] for item in group}
        for key, group in groupby(data, itemgetter('parent_id'))
}

I don't recommend writing a one-liner, but you can do it with sorted:

data = {
    key: {item['name']: item['id'] for item in group}
        for key, group in groupby(sorted(data, key=itemgetter('parent_id')), itemgetter('parent_id'))
}

So you want to play the comprehension game and you want to see a pro player at it.

Forget about itertools, forget about multiple statements. Here is the ultimate comprehension that will make any programmer working on your code throw the keyboard away and leave the room cursing you.

data = {parent_id: {d["name"]: d["id"] for d in [i for i in data if i["parent_id"] == parent_id]} for parent_id in set((j["parent_id"] for j in data))}

But for real though, don't do this in your code if it's going to be shared with someone.

Related