【问题标题】:Pythonic Way to reverse nested dictionaries反转嵌套字典的 Pythonic 方式
【发布时间】:2010-02-16 14:49:12
【问题描述】:

我有一个嵌套的人员和项目评级字典,以人员为键。人们可能会或可能不会共享项目。 示例:

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

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

【问题讨论】:

  • 在这种可读性很重要的情况下,理解并不总是一个好主意。
  • @jathanism,非常正确。我还在学习 Python,不确定是否有更简洁、更“pythonic”的实现来实现我想要做的事情。

标签: python list-comprehension


【解决方案1】:

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

【讨论】:

  • 这并不真正归功于 defaultdict,恕我直言,因为它真的很容易,只需添加行“flipped.setdefault(subkey, {})”
【解决方案2】:

我完全同意 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()]))])

【讨论】:

  • 不错。它看起来确实是一个非常复杂的理解,但提供它 +1。
  • 最好使用生成器表达式、字典的iter* 方法和chain.from_iterable(2.6 中的新功能)来完成。这样,只需要将集合保存在内存中,而不是临时构建的一堆列表。 dict((x, dict((k, d[k][x]) for k,v in d.iteritems() if x in d[k])) for x in set(itertools.chain.from_iterable(d.itervalues())))
【解决方案3】:

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

【讨论】:

  • 这是真的,值得考虑。但我获得的数据可能来自多种来源(json、xml、db 等),因此我正在寻找使用语言结构而不是依赖来源来处理事物的方法。
【解决方案4】:

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

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

【讨论】:

    【解决方案5】:

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

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-19
      • 2014-09-13
      • 1970-01-01
      • 2013-01-11
      • 1970-01-01
      • 2018-07-22
      • 2014-03-28
      • 2015-10-21
      相关资源
      最近更新 更多