简体   繁体   English

Pythonic方式来反转嵌套的词典

[英]Pythonic Way to reverse nested dictionaries

I have a nested dictionary of people and item ratings, with people as the key. 我有一个人和项目评级的嵌套字典,以人为关键。 people may or may not share items. 人们可能会也可能不会分享项目。 Example: 例:

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

I'm looking for the simplest way to flip these relations, and have a new nested dictionary with items as the key. 我正在寻找最简单的方法来翻转这些关系,并有一个新的嵌套字典,以项目为关键。 Example: 例:

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

What is the best way to do this? 做这个的最好方式是什么? Is it possible with a comprehension? 理解是否可能?

collections.defaultdict makes this pretty simple: 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))

Output: 输出:

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

I totally agree that Ryan Ginstrom's answer is the preferred way of doing this (for all practical purposes). 我完全同意Ryan Ginstrom的答案是这样做的首选方式(出于所有实际目的)。

But since the question also explicitely asks: 但由于这个问题也明确地问:

Is it possible with a comprehension? 理解是否可能?

I thought I'd chime in with a quick example as for how to do this with a list comprehension (it could be a good example for showing how nested list comphrehensions can quickly decrease readability). 我想我会用一个快速的例子来说明如何使用列表理解(这可能是一个很好的例子来展示嵌套列表的理解如何能够迅速降低可读性)。

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

This is easy enough to do (as others have shown), but depending on your needs you should also consider that for data with several pieces of information where you want to extract by any criterion, a database might be the best tool. 这很容易做到(正如其他人所示),但根据您的需要,您还应该考虑对于具有多条信息的数据,您希望按照任何标准提取这些信息,数据库可能是最好的工具。 The built-in sqlite3 module provides a low-overhead database that may, depending on what you are doing, serve you better than a nested dict. 内置的sqlite3模块提供了一个低开销的数据库,根据您的操作,它可能比嵌套的dict更好地为您提供服务。

Pandas can provide another option. 熊猫可以提供另一种选择。 Assume data is the input dictionary. 假设data是输入字典。

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

If you want just access reverse nested dictionaries, Save memory if the dictionary is too large to reverse. 如果您只想访问反向嵌套字典,请在字典太大而无法反转的情况下保存内存。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM