Home > database >  Inverting a dictionary with lists as values (which must not repeat as keys)
Inverting a dictionary with lists as values (which must not repeat as keys)

Time:10-17

I am currently working on a beginner's task (in Python): "Invert a dictionary: keys become values and values become keys. Original values are lists which, when transformed into keys, must not repeat!"

Firstly, I must write that I have seen several (similar) questions, but none are applicable to my task.

Secondly, I have tried writing a solution using nested for and if loops - unsuccessfully.

Then, I have written this code, after applying an internet solution:

def invert(dict1):
  invertedDict1 = dict()
  
  invertedDict1 = {value: key for key in dict1 for value in dict1[key]}
      
  #print(dict1)
  print(invertedDict1)    
  
dict1 = {1: [2, 3, 5],
         2: [1, 4],
         3: [1, 2],
         }

invert(dict1)

Output:

{2: 3, 3: 1, 5: 1, 1: 3, 4: 2}

It should be:

{1:[2,3], 2:[1,3], 3:[1], 4:[2], 5:[1]}

Does someone know where did I make the mistake (or mistakes)?

P.S. I'm brand new to Python and come from a C/C background, so please understand my lack of Python-specific knowledge

Thanks!

CodePudding user response:

The problem with your construction is key duplicates, which are not allowed in a dict. Also you have nothing in your code about list (for values).

The way is to use a defaultdict, with list as values. If the key isn't present, it puts an empty list, then appends the key in it.

from collections import defaultdict

def invert(dict1):
    invertedDict1 = defaultdict(list)
    for key, values in dict1.items():
        for value in values:
            invertedDict1[value].append(key)
    return invertedDict1


dict1 = {1: [2, 3, 5], 2: [1, 4], 3: [1, 2], }
print(invert(dict1))  # {2: [1, 3], 3: [1], 5: [1], 1: [2, 3], 4: [2]}

CodePudding user response:

You can do this easily with defaultdict:

from collections import defaultdict

d = defaultdict(list)

for k, v in dict1.items():
    for x in v:
        d[x].append(k)

print(d)
defaultdict(list, {2: [1, 3], 3: [1], 5: [1], 1: [2, 3], 4: [2]})

defaultdict(list) will always return a list when accessing a key: a new empty list [] if this the first time d[x] is accessed, the existing list of values [k1, k2, ...] associated to x if d[x] has been accessed before.

This way you can store all keys k associated the x in your lists

CodePudding user response:

azro's answer is excellent, but I just want to add an implementation without collections if it helps. I'll use dict.setdefault(default=[]) to insert a new list if needed, otherwise get the existing list.

def invert(d):
    inverted = {}
    for k, v in d.items():
        for x in v:
            L = inverted.setdefault(x, [])
            L.append(k)
    return inverted

dict1 = {1: [2, 3, 5], 2: [1, 4], 3: [1, 2]}
print(invert(dict1))  # -> {2: [1, 3], 3: [1], 5: [1], 1: [2, 3], 4: [2]}

This line with setdefault stands in for this:

if x not in inverted:
    inverted[x] = []
L = inverted[x]
  • Related