1

I wrote the following code and i cannot understand why my dictionary is being deleted alone with my list. Really hope you could help me with it.. iam kind of stuck here.

This is my code :

course_dict = {'I': 3, 'love': 3, 'self.py!': 2}
save_dict = {}

def inverse_dict(Recived_dict):
    global save_dict
    list_counter = 0
    new_dict = {}
    my_list = []
    current_value = list(Recived_dict.values())[0]
    for key, value in Recived_dict.items():
        if value == current_value:
            my_list.append(key)
            new_dict[value] = my_list
            save_dict = new_dict
        else:
            if list_counter == 0:
                del my_list[0:]
                list_counter =1
            my_list.append(key)
            new_dict[value] = my_list
            print(new_dict)

inverse_dict(course_dict)
Chris
  • 26,361
  • 5
  • 21
  • 42
Nimrod Itz
  • 11
  • 2
  • 3
    Welcome to stack overflow. What is your expected output? – will-hedges Jun 24 '22 at 15:22
  • 1
    What do you mean by "being deleted"? Please explain the expected behavior vs what you are seeing. – Lev Levitsky Jun 24 '22 at 15:23
  • 1
    I believe you are trying to invert the dictionary to map the values to the keys. There is an existing answer https://stackoverflow.com/a/485368/10498134. – jloh Jun 24 '22 at 15:23
  • 1
    I don't think it's strictly pertinent to this problem, but doing `global save_dict` and then assigning stuff to `save_dict` is a good way to get yourself confused. Instead of using `global` you should `return new_dict` at the end of your function, and then do `save_dict = inverse_dict(course_dict)` when you call the function. – Samwise Jun 24 '22 at 15:24
  • 1
    As far as this problem goes, note that you only have one `my_list` that you're sticking into multiple places in your dict. Whenever you do `del my_list[0:]`, you're emptying the list. – Samwise Jun 24 '22 at 15:25

2 Answers2

3

Since you have values that are not unique, you need a way to aggregate the original keys that correspond to the original values. You can start with a dictionary with the new keys and blank lists for the values, and then append the new values:

course_dict = {'I': 3, 'love': 3, 'self.py!': 2}


def inverse_dict(Recived_dict):
    new_dict = {v: [] for v in Recived_dict.values()}
    for k, v in Recived_dict.items():
        new_dict[v].append(k)
    print(new_dict)


inverse_dict(course_dict)
{3: ['I', 'love'], 2: ['self.py!']}

Assuming you will want to be able to use this new dictionary, your function should probably return the inverted dictionary:

def inverse_dict(Recived_dict):
    new_dict = {v: [] for v in Recived_dict.values()}
    for k, v in Recived_dict.items():
        new_dict[v].append(k)
    return new_dict


course_dict = {'I': 3, 'love': 3, 'self.py!': 2}
save_dict = inverse_dict(course_dict)
print(save_dict)
{3: ['I', 'love'], 2: ['self.py!']}
will-hedges
  • 1,254
  • 1
  • 9
  • 18
  • Much better, although I'd suggest making the first line `save_dict = {v: [] for v in Recived_dict.values()}`, and doing `return save_dict` at the end so the caller can actually get at it. :) – Samwise Jun 24 '22 at 15:27
2

defaultdict will make this much easier.

from collections import defaultdict

a = {3: 'foo', 5: 'foo', 4: 'bar'}
d = defaultdict(list)

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

Result:

defaultdict(<class 'list'>, {'foo': [3, 5], 'bar': [4]})

You might also use itertools.groupby.\

>>> from itertools import groupby
>>> from operator import itemgetter
>>> a = {3: 'foo', 5: 'foo', 4: 'bar'}
>>> {k: [b for b, _ in v]
...  for k, v in groupby(
...    sorted(
...      a.items(),
...      key=itemgetter(1)
...    ),
...    key=itemgetter(1)
...  )}
{'bar': [4], 'foo': [3, 5]}
Chris
  • 26,361
  • 5
  • 21
  • 42