用列表值反转字典

Inverting a dictionary with list values

所以,我将这个索引作为字典。

index = {'Testfil2.txt': ['nisse', 'hue', 'abe', 'pind'], 'Testfil1.txt': ['hue', 'abe', 
'tosse', 'svend']}

我需要反转索引,这样它将成为一个字典,其中重复的值合并到一个键中,两个原始键作为值,如下所示:

inverse = {'nisse' : ['Testfil2.txt'], 'hue' : ['Testfil2.txt', 'Testfil1.txt'], 
           'abe' : ['Testfil2.txt', 'Testfil1.txt'], 'pind' : ['Testfil2.txt'], 
           'tosse' : ['Testfil1.txt'], 'svend' : ['Testfil1.txt']

是的,上面是我手写的。

我的课本有这样的字典倒排功能:

def invert_dict(d): 
    inverse = dict() 
    for key in d: 
        val = d[key] 
        if val not in inverse: 
            inverse[val] = [key] 
        else: 
            inverse[val].append(key) 
    return inverse

它适用于简单的 key:value 对

但是,当我尝试使用具有列表作为值的字典的函数时,例如我的 index 我收到此错误消息:

invert_dict(index)

Traceback (most recent call last):
    File "<pyshell#153>", line 1, in <module>
invert_dict(index)
    File "<pyshell#150>", line 5, in invert_dict
if val not in inverse:
TypeError: unhashable type: 'list'

我已经搜索了一个小时来寻找解决方案,这本书没有帮助,我怀疑我可以以某种方式使用元组,但我不确定如何使用。有帮助吗?

您不能将 list 对象用作字典键,因为它们应该是可哈希对象。您可以遍历您的项目并使用 dict.setdefault 方法来创建预期结果:

>>> new = {}
>>> 
>>> for k,value in index.items():
...     for v in value:
...         new.setdefault(v,[]).append(k)
... 
>>> new
{'hue': ['Testfil2.txt', 'Testfil1.txt'], 'svend': ['Testfil1.txt'], 'abe': ['Testfil2.txt', 'Testfil1.txt'], 'tosse': ['Testfil1.txt'], 'pind': ['Testfil2.txt'], 'nisse': ['Testfil2.txt']}

并且如果您正在处理更大的数据集以拒绝在每次调用 setdefault() 方法时创建一个空列表,您可以使用 collections.defaultdict() 它将在遇到新密钥。

from collections import defaultdict

new = defaultdict(list)
for k,value in index.items():
    for v in value:
        new[v].append(k)

>>> new
defaultdict(<type 'list'>, {'hue': ['Testfil2.txt', 'Testfil1.txt'], 'svend': ['Testfil1.txt'], 'abe': ['Testfil2.txt', 'Testfil1.txt'], 'tosse': ['Testfil1.txt'], 'pind': ['Testfil2.txt'], 'nisse': ['Testfil2.txt']})

我已经试过了,你想使用 val not in inverse,但如果是 "list is in a dict",则无法检查。 (val 是一个列表)

对于您的代码,只需简单更改即可满足您的要求:

def invert_dict(d): 
    inverse = dict() 
    for key in d: 
        # Go through the list that is saved in the dict:
        for item in d[key]:
            # Check if in the inverted dict the key exists
            if item not in inverse: 
                # If not create a new list
                inverse[item] = [key] 
            else: 
                inverse[item].append(key) 
    return inverse

我的字典逆向解决方案。但是,它创建了一个新字典 new_dic:

new_dic = {}
for k,v in index.items():
    for x in v:
        new_dic.setdefault(x,[]).append(k)

输出:

{'tosse': ['Testfil1.txt'], 'nisse': ['Testfil2.txt'], 'svend': ['Testfil1.txt'], 'abe': ['Testfil1.txt', 'Testfil2.txt'], 'pind': ['Testfil2.txt'], 'hue': ['Testfil1.txt', 'Testfil2.txt']}

作为嵌套理解:

inverse = { v: k for k, l in index.items() for v in l }

或者,也许更清楚:

inverse = { 
            new_key: index_key                              #body
            for index_key, index_value in index.items()     #outer loop
                for new_key in index_value                  #inner loop
            }

大致相当于:

new_keys    =   []
new_values  =   []

for index_key, index_value in index.items():
    for new_key in index_value:
        new_keys.append(new_key)
        new_values.append(index_key)
        
inverse     =   dict(zip(new_keys,new_values))

使用解包运算符 * 和嵌套压缩的两个线性解决方案。

for k,v in old_dict.items():
    new_dict = {**new_dict,**{vi:k for vi in v}}