简体   繁体   中英

Restructuring the hierarchy of dictionaries in Python?

If I have a nested dictionary in Python, is there any way to restructure it based on keys?

I'm bad at explaining, so I'll give a little example.

d = {'A':{'a':[1,2,3],'b':[3,4,5],'c':[6,7,8]},
     'B':{'a':[7,8,9],'b':[4,3,2],'d':[0,0,0]}}

Re-organize like this

newd = {'a':{'A':[1,2,3],'B':[7,8,9]},
        'b':{'A':[3,4,5],'B':[4,3,2]},
        'c':{'A':[6,7,8]},
        'd':{'B':[0,0,0]}}

Given some function with inputs like

def mysteryfunc(olddict,newkeyorder):
    ????

mysteryfunc(d,[1,0])

Where the [1,0] list passed means to put the dictionaries 2nd level of keys in the first level and the first level in the 2nd level. Obviously the values need to be associated with their unique key values.

Edit: Looking for an answer that covers the general case, with arbitrary unknown nested dictionary depth.

Input:

d = {'A':{'a':[1,2,3],'b':[3,4,5],'c':[6,7,8]},
     'B':{'a':[7,8,9],'b':[4,3,2],'d':[0,0,0]}}

inner_dict={}
for k,v in d.items():
    print(k)
    for ka,va in v.items():
        val_list=[]
        if ka not in inner_dict:
            val_dict={}
            val_dict[k]=va
            inner_dict[ka]=val_dict
        else:
            val_dict=inner_dict[ka]
            val_dict[k]=va
            inner_dict[ka]=val_dict

Output:

{'a': {'A': [1, 2, 3], 'B': [7, 8, 9]},
 'b': {'A': [3, 4, 5], 'B': [4, 3, 2]},
 'c': {'A': [6, 7, 8]},
 'd': {'B': [0, 0, 0]}}

you can use 2 for loops, one to iterate over each key, value pair and the second for loop to iterate over the nested dict, at each step form the second for loop iteration you can build your desired output:

from collections import defaultdict

new_dict = defaultdict(dict)

for k0, v0 in d.items():
    for k1, v1 in v0.items():
        new_dict[k1][k0] = v1

print(dict(new_dict)) 

output:

{'a': {'A': [1, 2, 3], 'B': [7, 8, 9]},
 'b': {'A': [3, 4, 5], 'B': [4, 3, 2]},
 'c': {'A': [6, 7, 8]},
 'd': {'B': [0, 0, 0]}}

You can use recursion with a generator to handle input of arbitrary depth:

def paths(d, c = []):
   for a, b in d.items():
      yield from ([((c+[a])[::-1], b)] if not isinstance(b, dict) else paths(b, c+[a]))


from collections import defaultdict
def group(d):
   _d = defaultdict(list)
   for [a, *b], c in d:
     _d[a].append([b, c])
   return {a:b[-1][-1] if not b[0][0] else group(b) for a, b in _d.items()}

print(group(list(paths(d))))

Output:

{'a': {'A': [1, 2, 3], 'B': [7, 8, 9]}, 'b': {'A': [3, 4, 5], 'B': [4, 3, 2]}, 'c': {'A': [6, 7, 8]}, 'd': {'B': [0, 0, 0]}}

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