Pythonic方式来反转嵌套的词典

时间:2010-02-16 14:49:13

标签: python list-comprehension

我有一个人和项目评级的嵌套字典,以人为关键。人们可能会也可能不会分享项目。 例如:

{
 '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 个答案:

答案 0 :(得分:18)

collections.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}}

答案 1 :(得分:4)

我完全同意Ryan Ginstrom的答案是这样做的首选方式(出于所有实际目的)。

但是,问题也明确地问:

是否可以理解?

我以为我会用一个简单的例子来说明如何使用列表理解(这可能是一个很好的例子来展示嵌套列表理解如何迅速降低可读性)。

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

答案 2 :(得分:1)

这很容易做到(正如其他人所示),但根据您的需要,您还应该考虑对于包含您想要按任何标准提取的多条信息的数据,数据库可能是最好的工具。内置的sqlite3模块提供了一个低开销的数据库,根据您的操作,它可能比嵌套的字典更好地为您提供服务。

答案 3 :(得分:0)

熊猫可以提供另一种选择。假设data是输入字典。

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

答案 4 :(得分:0)

如果您只想访问反向嵌套词典, 如果字典太大而无法反转,请节省内存。

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