17

I have a dictionary with almost 100,000 (key, value) pairs and the majority of the keys map to the same values. For example:

mydict =  {'a': 1, 'c': 2, 'b': 1, 'e': 2, 'd': 3, 'h': 1, 'j': 3}

What I want to do, is to reverse the dictionary so that each value in mydict is going to be a key at the reverse_dict and is going to map to a list of all the mydict.keys() that used to map to that value in mydict. So based on the example above I would get:

reversed_dict = {1: ['a', 'b', 'h'], 2: ['c', 'e'] , 3: ['d', 'j']} 

I came up with a solution that is very expensive and I want to hear any ideas for doing this more efficiently than this:

reversed_dict = {}
for value in mydict.values():
    reversed_dict[value] = []
    for key in mydict.keys():
        if mydict[key] == value:
            if key not in reversed_dict[value]: 
                reversed_dict[value].append(key)
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
Galois
  • 329
  • 1
  • 3
  • 10
  • Does this answer your question? [Reverse / invert a dictionary mapping](https://stackoverflow.com/questions/483666/reverse-invert-a-dictionary-mapping) – mkrieger1 May 06 '22 at 14:53

7 Answers7

27

Using collections.defaultdict:

from collections import defaultdict

reversed_dict = defaultdict(list)
for key, value in mydict.items():
    reversed_dict[value].append(key)
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
joaquin
  • 82,968
  • 29
  • 138
  • 152
5
reversed_dict = {}
for key, value in mydict.items():
    reversed_dict.setdefault(value, [])
    reversed_dict[value].append(key)
VahidB
  • 145
  • 2
  • 8
1

I think you're wasting a few cycles by replacing a key with the same key again and again...

reversed_dict = {}
for value in mydict.values():
    if value not in reversed_dict.keys(): #checking to be sure it hasn't been done.
        reversed_dict[value] = []
        for key in mydict.keys():
            if mydict[key] == value:
                if key not in reversed_dict[value]: reversed_dict[value].append(key)
eric
  • 19
  • 1
1
for k,v in dict.iteritems():
    try:
      reversed_dict[v].append(k)
    except KeyError:
       reversed_dict[v]=[k]
Florian Diesch
  • 1,025
  • 10
  • 16
1

Using itertools.groupby:

from operator import itemgetter
from itertools import groupby

snd = itemgetter(1)

def sort_and_group(itr, f):
    return groupby(sorted(itr, key=f), f)

mydict =  {'a': 1, 'c': 2, 'b': 1, 'e': 2, 'd': 3, 'h': 1, 'j': 3}
reversed_dict = {number: [char for char,_ in v] 
                 for number, v in sort_and_group(mydict.items(), snd)}
chepner
  • 497,756
  • 71
  • 530
  • 681
0
reversed_dict = collections.defaultdict(list)
for key, value in dict_.iteritems():
  reversed_dict[value].append(key)
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
0
def reverse_dict(mydict):
    v={}
    for x,y in mydict.items():
        if  y not in v:
            v[y]=[x]
        else:
            v[y].append(x)
    return v

print(reverse_dict(mydict))
pmadhu
  • 3,373
  • 2
  • 11
  • 23
  • 3
    Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. – NKSM Aug 27 '21 at 13:19
  • This looks like a rehash of a couple of existing answers. Please read [answer] and avoid repeating answers, especially on old questions (this one is over eleven years old). – ChrisGPT was on strike Aug 27 '21 at 17:56