Reputation: 567
I have a python dictionary that has 3 embedded layers, like below (there are many keys in each layer):
my_dict = {key1:{key2:{key3:some_value}}}
Now I want to reconstruct the dictionary by moving key3 as the very first layer. So the dictionary would look like:
my_dict = {key3:{key1:{key2:some_value}}}
I know the silly method of using 3 for loops to reconstruct the whole thing, like
my_new_dict = {}
for key1 in my_dict.keys():
for key2 in my_dict[key1].keys():
for key3 in my_dict[key1][key2].keys():
### a bunch of code to check if the key already exists and
### to move values into the new dictionary from scratch
I wonder if there are better ways to do it. Or maybe dictionary is not the best way to represent such data structure. Then what's a better way of constructing such data? I want to do the reconstruction because I want to do some computation that loops by key3 first, but I cannot get to key3 without looping with key1 and key2 first with my original dictionary.
Upvotes: 0
Views: 297
Reputation: 1544
Well it doesn't have to be that complicated, especially with defaultdict
from collections import defaultdict
tree = lambda: defaultdict(tree)
new_dict = tree()
for key1 in my_dict:
for key2 in my_dict[key1]:
for key3 in my_dict[key1][key2]:
new_dict[key3][key1][key2] = my_dict[key1][key2][key3]
The only problem is that you're now left with a bunch of defaultdicts, which have bad __repr__
's.
Upvotes: 1
Reputation: 104792
The "bunch of code" doesn't actually need to be very complicated. If you use dict.setdefault
to create new intermediate dictionaries as needed, the supposedly complicated part becomes a one-liner. I would also suggest iterating over the items
of your dictionaries, rather than indexing them with the keys:
result = {}
for key1, middle_dict in my_dict.items():
for key2, inner_dict in middle_dict.items():
for key3, value in inner_dict.items():
result.setdefault(key3, {}).setdefault(key1, {})[key2] = value
If you're using Python 2, you may want to use iteritems
rather than items
, as it doesn't allocate a list to hold all the values. In Python 3, items
returns an iterable "view" object that doesn't require so much memory.
Upvotes: 0