2016-02-18 2 views
3

Итак, у меня есть этот индекс как dict.Инвертирование словаря со значениями списка

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

Мне нужно, чтобы инвертировать индекс, так это будет Dict с дубликатами значений объединены в один ключ с 2 оригинальных ключей в качестве значений, например:

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 

Это прекрасно работает для простых пар ключ: значение

НО, когда я пытаюсь эту функцию с Словаре, который имеет списки в качестве значений, таких как мой 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' 

Я искал в течение часа, ища решения, книга не поможет, и я подозреваю, что Я могу каким-то образом использовать кортежи, но я не уверен, как это сделать. Любая помощь?

ответ

1

Я попытался вокруг, и вы хотите использовать val not in inverse, но она не может быть проверена, если «список в Словаре». (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 
1

Вы не можете использовать объекты 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']}) 
+1

Это не держит 'list' всех ключей, связанных с ГИ значение ven, оно уменьшает все, кроме последнего увиденного. – ShadowRanger

+0

Да, столько я собрал! Это довольно хорошо, мне просто нужны ключи, чтобы иметь несколько значений, например. ''' hue'' имеет как' 'Testfil1.txt'' AND' 'Testfil2.txt'', так и все, что идеально. – Vestergaardish

+0

@ShadowRanger Да, просто исправлено. – Kasramvd

4

Мое решение для обратного словаря, как всегда это создает новый словарь 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']} 
+2

FYI, вся бессмысленность 'try' /' except' может быть значительно сокращена путем создания 'new_dic'' 'collection.defaultdict (list)' или с помощью простого 'dict', заменяющего весь' try'/'except' с просто 'new_dic.setdefault (x, []). append (k)', избегая необходимости обрабатывать «ключ существует» и «ключ отсутствует» отдельно. – ShadowRanger

+1

@ShadowRanger, очень хорошая точка, спасибо! – Arman

Смежные вопросы