Перестройка иерархии словарей в Python? - PullRequest
2 голосов
/ 07 февраля 2020

Если у меня есть вложенный словарь в Python, есть ли способ реструктурировать его по ключам?

Я плохо объясняю, поэтому приведу небольшой пример.

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]}}

Реорганизовать таким образом

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]}}

Учитывая некоторую функцию с такими входными данными, как

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

mysteryfunc(d,[1,0])

Где переданный список [1,0] означает поместить словари на 2-е место уровень клавиш на первом уровне и первый уровень на 2-м уровне. Очевидно, что значения должны быть связаны с их уникальными значениями ключа.

Редактировать: Искать ответ, который охватывает общий случай, с произвольной неизвестной глубиной вложенного словаря.

Ответы [ 3 ]

4 голосов
/ 07 февраля 2020

Вход:

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

Выход:

{'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]}}
2 голосов
/ 07 февраля 2020

вы можете использовать 2 для циклов, один для итерации по каждому ключу, паре значений, а второй для l oop для итерации по вложенному dict, на каждом шаге формируйте вторую для итерации l oop, которую вы можете построить желаемый вывод:

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)) 

вывод:

{'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]}}
1 голос
/ 07 февраля 2020

Вы можете использовать рекурсию с генератором для обработки ввода произвольной глубины:

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))))

Вывод:

{'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]}}
...