Home > Net >  How to invert dictionary with multiple values of each key?
How to invert dictionary with multiple values of each key?

Time:12-26

I have been working on this forever. I have the following dictionary.

Subject1='Math'
Subject2='English'
Subject3='Chemstry'
Subject4='Physics'
Subject5='Geology'
Subject6='PE'
Subject7='Music'
Subject8='Psychology'
Subject9='Politics'
Subject10='Acting'

dict_1 = {(Subject1, Subject2):['Michael','James','Lydia'],
          (Subject3, Subject4):['Michael','Lydia','James'],
          (Subject5, Subject6):['Tom'],
          (Subject7, Subject8):[],
          (Subject9, Subject10):[]
}

I want to inverse the dictionary so that it will look like:

{['Michael', 'James', 'Lydia']: {(Subject1, Subject2), (Subject3, Subject4)}, 
 ['Tom']: {(Subject5, Subject6)}, 
 []: {(Subject7, Subject8), (Subject9, Subject10)} }

I tried

from collections import defaultdict

new_tel = defaultdict(list)
for key, value in dict_1.items():
    new_tel[value].append(key)

This worked for hashable type but not unhashable type list. Maybe I can join the string of ['Michael','James','Lydia'] to 'James Lydia Michael' so that it can be a valid key? How do I sort the elements in the list ['Michael','James','Lydia'] and ['Michael','Lydia','James'] so that they are in alphabetical order before I join them?

This is a more achievable output:

{'James Lydia Michael': {(Subject1, Subject2), (Subject3, Subject4)}, 
 'Tom': {(Subject5, Subject6)}, 
 'None': {(Subject7, Subject8), (Subject9, Subject10)} }

CodePudding user response:

Dictionary keys can't be lists but it can be tuples. So you can do something like below. Sort the values, make them tuples to use as keys and use dict.setdefault:

out = {}
for k,v in dict_1.items():
    out.setdefault(tuple(sorted(v)), set()).add(k)

Output:

{('James', 'Lydia', 'Michael'): {('Chemstry', 'Physics'), ('Math', 'English')},
 ('Tom',): {('Geology', 'PE')},
 (): {('Music', 'Psychology'), ('Politics', 'Acting')}}

CodePudding user response:

As told in the question comments lists are unhashable. if you can use tuple instead, "Dict Comprehensions" is a good way. More info: https://www.python.org/dev/peps/pep-0274/.

dict_reverse = {tuple(dict_1[key]): key for key in dict_1.keys()}

CodePudding user response:

Easiest would be to use a tuple as key type

for key, value in dict_1.items():
    new_tel[tuple(sorted(value))].append(key)


{('James', 'Lydia', 'Michael'): [('Math', 'English'), ('Chemstry', 'Physics')], 
 ('Tom',): [('Geology', 'PE')],  
 (): [('Music', 'Psychology'), ('Politics', 'Acting')]})

If you join to set the key type as str

for key, value in dict_1.items():
    new_tel[" ".join(sorted(value))].append(key)


{'James Lydia Michael': [('Math', 'English'), ('Chemstry', 'Physics')], 
 'Tom': [('Geology', 'PE')], 
 '': [('Music', 'Psychology'), ('Politics', 'Acting')]})
  • Related