954,515 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

Invert Dict, with with key values as lists

want to do: dict = {'1': ['a'],'2': ['a', 'b', 'c']}
invert it to: inv_dict = {'a':['1','2'],'b':['2'],'c':['2']}


i know the one liner, if the dict was one to one, inverse = dict((d[k], k) for k in d) can I modify this to work if it was not one to one?

My original attempt: tried to get all of the values from the dict and made it a list then deleted duplicates, using set, then compared original dict keys to check if the certain value existed in that key, if true then change the key in list and append. I can post the code, if needed? Any other suggested way? I feel there has to be a easier way than this.

slash16
Newbie Poster
3 posts since Nov 2011
Reputation Points: 23
Solved Threads: 0
 

Not simple one liner (of course you can put everything in one line, but it becomes less readable), but I would do:

>>> d
{'1': ['a'], '2': ['a', 'b', 'c']}
>>> values = set(a for b in d.values() for a in b)
>>> values
set(['a', 'c', 'b'])
>>> reverse_d = dict((new_key, [key for key,value in d.items() if new_key in value]) for new_key in values)
>>> reverse_d
{'a': ['1', '2'], 'c': ['2'], 'b': ['2']}
>>>
pyTony
pyMod
Moderator
5,359 posts since Apr 2010
Reputation Points: 782
Solved Threads: 852
 

Another way

>>> from operator import itemgetter
>>> from itertools import groupby
>>> dic = {'1': ['a', 'c'],'2': ['a', 'b', 'c'], '3': ['b']}
>>> dict((x, list(t[1] for t in group)) for (x, group) in groupby(sorted(((j, k) for k, v in dic.items() for j in v), key=itemgetter(0)), key=itemgetter(0)))
{'a': ['1', '2'], 'c': ['1', '2'], 'b': ['2', '3']}
Gribouillis
Posting Maven
Moderator
2,786 posts since Jul 2008
Reputation Points: 1,044
Solved Threads: 691
 

Wow, thank you so much. But can you explain how the following line works, as in what each thing does?

>>> reverse_d = dict((new_key, [key for key,value in d.items() if new_key in value]) for new_key in values)



Sorry new to python, it seems much different then pascal or php, which I am used to.

slash16
Newbie Poster
3 posts since Nov 2011
Reputation Points: 23
Solved Threads: 0
 
reverse_d = dict( # invoking __init__ method of dict class to create dictionary
             # simple value from the generator in values as key
            (new_key, 
              # value of dictionary by 
              #list comprehension filtering the items by the if condition
              # http://docs.python.org/tutorial/datastructures.html#list-comprehensions
              [key for key,value in d.items() if new_key in value]) 
            # generator for to go through each value in set values (unique)
            for new_key in values)
pyTony
pyMod
Moderator
5,359 posts since Apr 2010
Reputation Points: 782
Solved Threads: 852
 
reverse_d = dict( # invoking __init__ method of dict class to create dictionary
             # simple value from the generator in values as key
            (new_key, 
              # value of dictionary by 
              #list comprehension filtering the items by the if condition
              # http://docs.python.org/tutorial/datastructures.html#list-comprehensions
              [key for key,value in d.items() if new_key in value]) 
            # generator for to go through each value in set values (unique)
            for new_key in values)


wow, so it does what i was attempting to do in 50 lines, in 2 lines. thank you appreciated a lot.

slash16
Newbie Poster
3 posts since Nov 2011
Reputation Points: 23
Solved Threads: 0
 

Do not be discouraged even it sounds bit excessive. you get hang of it bit by bit. You had good pseudo-code for whatt to do, that is main thing.

Good thing is that you can write so readable code in Python, only it means that if you use some code you wrote more than week before (or later one month), you are very likely ashamed what you did and fix many things. I did anagram program about two times per week at beginning, sometimes reading my earlier code but not copying to get fluent. The code you can find in code snippet part posted 11.11.11 is version I tried and failed to realize at that time. Main action find_anagrams is only few lines long. I also have around twice faster version, but this simple program program is lot faster than you can read, even in cases when you have tens of thousands of results a it yield them one by one be generator.

pyTony
pyMod
Moderator
5,359 posts since Apr 2010
Reputation Points: 782
Solved Threads: 852
 

This question has already been solved

Post: Markdown Syntax: Formatting Help
You