【问题标题】:In python, how do I invert a 2D dictionary?在 python 中,如何反转二维字典?
【发布时间】:2019-04-09 05:37:52
【问题描述】:

我有一本如下形式的字典

dict = {
   "a" : {"a1" : 1},
   "b" : {"a2" : 1, "a3" : 2},
   "c" : {"a2" : 3, "a4" : 3}
}

我需要反向索引字典,格式如下:

inverseDict = {
    "a1" : {"a" : 1},
    "a2" : {"b" : 1, "c" : 3},
    "a3" : {"b" : 2},
    "a4" : {"c" : 3}
}

基本上

inverseDict = {dict.value.key : { dict.key : dict.value.value}}

所以本质上,我需要将值的键作为键,将键作为值的键,同时加入重复新键的结果等。

我试过了

ks = dict.keys()
vals = dict.values()

ks2 = vals.keys()
vals2 = vals.values()

如果这有任何意义

但是我遇到了一个错误

'dict_values' object has no attribute 'keys'

据我了解,这是因为 dict.values() .keys() .items() 返回“视图”而不是实际元素本身,但我不知道如何解决这个问题。

还有一个更有效的解决方案我应该考虑,因为我的实际字典非常大(约 10k 个键),并且生成的逆字典也很大(>3k 个键)

【问题讨论】:

  • 只是一个简短的评论,您需要避免使用内置关键字dict 进行赋值。您最终会遮蔽 dict 内置对象。
  • @Idlehands 这不是我的dict 的实际名称,只是一个“虚拟”名称。但是是的,我明白你的意思

标签: python python-3.x dictionary


【解决方案1】:

使用collections.defaultdict(dict) 和双循环相当简单:

d = {
    "a" : {"a1" : 1},
    "b" : {"a2" : 1, "a3" : 2},
    "c" : {"a2" : 3, "a4" : 3},
}

import collections

inverted = collections.defaultdict(dict)

for key,subd in d.items():
    for k,v in subd.items():  # no inspiration for key/value names...
        inverted[k][key] = v

inverted

{'a1': {'a': 1},
 'a2': {'b': 1, 'c': 3},
 'a3': {'b': 2},
 'a4': {'c': 3}}

使用defaultdict 避免测试条目是否已经存在,如果不存在则创建字典值。因此,只需按预期顺序无脑添加键/值即可。

请注意,那些需要将项目处理成多个对象的问题很难使用推导式解决。

【讨论】:

  • 嗯,它绝对有效,但我不明白为什么 inverted=collections.defaultdict(dict) 比使用 inverted = {} 更好。
  • 因为使用裸字典,您必须测试字典是否已经存在,如果不存在则创建它:更多行,更慢。如果需要,您可以将其转换回 dictinverted = dict(inverted)
  • 但在这两种情况下,您都创建了一个空的inverted 并继续用值填充它?我没有得到什么吗?
  • 使用默认字典,只要在inverted["a_key"] 创建一个字典在a_key 键下如果不存在。您不必担心字典的初始化。
【解决方案2】:

另一种没有标准库的解决方案......但让-弗朗索瓦·法布尔的回答更简洁,可能更容易模块化。如有疑问,请使用标准库。

OriginalDict = ... (Original dict items)
InvertedDict = {}
for k, v in OriginalDict.items():
    for k_, v_ in v.items():
        if InvertedDict.get(k_) is None:
            InvertedDict[k_] = {}
        InvertedDict[k_][k] = v_

【讨论】:

    【解决方案3】:

    你可以使用setdefault:

    d = {
        'a': {'a1': 1},
        'b': {'a2': 1, 'a3': 2},
        'c': {'a2': 3, 'a4': 3}
    }
    
    result = {}
    for ok, vs in d.items():
        for ik, v in vs.items():
            result.setdefault(ik, {})[ok] = v
    
    print(result)
    

    输出

    {'a4': {'c': 3}, 'a1': {'a': 1}, 'a2': {'c': 3, 'b': 1}, 'a3': {'b': 2}}
    

    函数setdefaultdefaultdict的用法类似。

    【讨论】:

    • 很好的解决方案。唯一的缺点是即使找到了键,它也会创建一个空的 dict 对象。 setdefault 更适合与更可能被实习的不可变对象一起使用,或者创建一次并存储在setdefault 可以引用的变量中
    猜你喜欢
    • 2014-11-13
    • 2013-12-15
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-28
    相关资源
    最近更新 更多