Pythonic Путь, чтобы полностью изменить вложенные словари - PullRequest
10 голосов
/ 16 февраля 2010

У меня есть вложенный словарь людей и рейтингов предметов, с людьми в качестве ключа. люди могут или не могут делиться предметами. Пример:

{
 'Bob' : {'item1':3, 'item2':8, 'item3':6},
 'Jim' : {'item1':6, 'item4':7},
 'Amy' : {'item1':6,'item2':5,'item3':9,'item4':2}
}

Я ищу самый простой способ перевернуть эти отношения и получить новый вложенный словарь с элементами в качестве ключа. Пример:

{'item1' : {'Bob':3, 'Jim':6, 'Amy':6},
 'item2' : {'Bob':8, 'Amy':5},
 'item3' : {'Bob':6, 'Amy':9},
 'item4' : {'Jim':7, 'Amy':2}
}

Каков наилучший способ сделать это? Возможно ли это с пониманием?

Ответы [ 5 ]

18 голосов
/ 16 февраля 2010

collection.defaultdict делает это довольно просто:

from collections import defaultdict
import pprint

data = {
 'Bob' : {'item1':3, 'item2':8, 'item3':6},
 'Jim' : {'item1':6, 'item4':7},
 'Amy' : {'item1':6,'item2':5,'item3':9,'item4':2}
}

flipped = defaultdict(dict)
for key, val in data.items():
    for subkey, subval in val.items():
        flipped[subkey][key] = subval

pprint.pprint(dict(flipped))

Выход:

{'item1': {'Amy': 6, 'Bob': 3, 'Jim': 6},
 'item2': {'Amy': 5, 'Bob': 8},
 'item3': {'Amy': 9, 'Bob': 6},
 'item4': {'Amy': 2, 'Jim': 7}}
4 голосов
/ 16 февраля 2010

Я полностью согласен с тем, что ответ Райана Гинстрома является предпочтительным способом сделать это (для всех практических целей).

Но так как вопрос также явно задает:

Возможно ли это с пониманием?

Я подумала, что мне следует привести быстрый пример того, как сделать это с помощью понимания списка (это может быть хорошим примером для демонстрации того, как вложенные списки могут быстро снизить читаемость).

import itertools

d = {
 'Bob' : {'item1':3, 'item2':8, 'item3':6},
 'Jim' : {'item1':6, 'item4':7},
 'Amy' : {'item1':6,'item2':5,'item3':9,'item4':2}
}

print dict([(x, dict([(k, d[k][x]) for k,v in d.items() if x in d[k]])) 
            for x in set(itertools.chain(*[z for z in d.values()]))])
1 голос
/ 16 февраля 2010

Это достаточно легко сделать (как показали другие), но в зависимости от ваших потребностей вы также должны учитывать, что для данных с несколькими частями информации, которые вы хотите извлечь по любому критерию, база данных может быть лучшим инструментом. Встроенный модуль sqlite3 предоставляет базу данных с низкими издержками, которая, в зависимости от того, что вы делаете, может служить вам лучше, чем вложенный запрос.

0 голосов
/ 07 ноября 2017

Если вы хотите просто получить доступ к обратным вложенным словарям, Сохраните память, если словарь слишком велик, чтобы его можно было перевернуть.

class mdict2(dict):
    def __init__(self, parent, key1):
        self.parent = parent
        self.key1 = key1

    def __getitem__(self, key2):
        return self.parent.mirror[key2][self.key1]


class mdict(dict):
    def __init__(self, mirror):
        self.mirror = mirror

    def __getitem__(self, key):
        return mdict2(self, key)

d0 = {
 'Bob' : {'item1':3, 'item2':8, 'item3':6},
 'Jim' : {'item1':6, 'item4':7},
 'Amy' : {'item1':6,'item2':5,'item3':9,'item4':2}
}
d1 = mdict(d0)

d0['Amy']['item1'] == d1['item1']['Amy']
# True
0 голосов
/ 24 декабря 2016

Панды могут предоставить другой вариант. Предположим, data является входным словарем.

import pandas as pd
output = {i:s.dropna().to_dict() for i, s in pd.DataFrame(data).T.iteritems()}
...