Pythonic反转嵌套字典的方法

Pythonic反转嵌套字典的方法,python,list-comprehension,Python,List Comprehension,我有一个嵌套的人员和项目评级词典,其中人员是关键。人们可以共享或不共享项目。 例如: 我正在寻找翻转这些关系的最简单方法,并拥有一个以项为键的新嵌套字典。 例如: 最好的方法是什么?理解有可能吗?使这一点非常简单: from collections import defaultdict import pprint data = { 'Bob' : {'item1':3, 'item2':8, 'item3':6}, 'Jim' : {'item1':6, 'item4':7}, 'Amy

我有一个嵌套的人员和项目评级词典,其中人员是关键。人们可以共享或不共享项目。 例如:

我正在寻找翻转这些关系的最简单方法,并拥有一个以项为键的新嵌套字典。 例如:

最好的方法是什么?理解有可能吗?

使这一点非常简单:

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

这是很容易做到的(正如其他人所示),但是根据你的需要,你也应该考虑到,对于有多条信息的数据,你想用任何标准来提取,数据库可能是最好的工具。内置的

sqlite3
模块提供了一个低开销的数据库,根据您所做的事情,它可能比嵌套的dict更好地为您服务。

我完全同意Ryan Ginstrom的答案是实现这一点的首选方法(出于所有实际目的)

但既然问题也明确提出:

有理解力吗?

我想我应该用一个简单的例子来说明如何通过列表理解来做到这一点(这可能是一个很好的例子,说明嵌套列表组合如何快速降低可读性)


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

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

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

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

在这种可读性很重要的情况下,理解不一定总是一个好主意。@jathanism,非常正确。我仍在学习Python,不确定是否有一个更干净、更“pythonic”的实现来实现我试图做的事情。这是真的,值得考虑。但是我得到的数据可能来自各种来源(json、xml、db等),因此我正在寻找使用语言构造而不是依赖source.nice的方法。它看起来确实是一个相当复杂的理解,但提供它需要+1。这最好是通过生成器表达式、字典的
iter*
方法和
chain.from\u iterable
(2.6中新增)来实现。这样,只需要将集合保存在内存中,而不是临时构造一组列表
dict((x,dict((k,d[k][x])表示k,v在d.iteritems()中,如果x在d[k]))表示x在set(itertools.chain.from_iterable(d.itervalues())
defaultdict,IMHO并不是很容易做到的,因为没有它也很容易,只需添加一行“flipped.setdefault(subkey,{}”
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()]))])
import pandas as pd
output = {i:s.dropna().to_dict() for i, s in pd.DataFrame(data).T.iteritems()}
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