By Brian M. Hunt


2009-01-27 14:46:09 8 Comments

Given a dictionary like so:

my_map = { 'a': 1, 'b':2 }

How can one invert this map to get:

inv_map = { 1: 'a', 2: 'b' }

EDITOR NOTE: map changed to my_map to avoid conflicts with the built-in function, map. Some comments may be affected below.

30 comments

@ARGeo 2019-01-10 05:55:16

For instance, you have the following dictionary:

dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}

And you wanna get it in such an inverted form:

inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}

First Solution. For inverting key-value pairs in your dictionary use a for-loop approach:

# Use this code to invert dictionaries that have non-unique values

inverted_dict = dictio()
for key, value in dict.items():
    inverted_dict.setdefault(value, list()).append(key)

Second Solution. Use a dictionary comprehension approach for inversion:

# Use this code to invert dictionaries that have unique values

inverted_dict = {value: key for key, value in dict.items()}

Third Solution. Use reverting the inversion approach:

# Use this code to invert dictionaries that have lists of values

dict = {value: key for key in inverted_dict for value in my_map[key]}

@Seshadri VS 2018-11-07 22:36:35

As per my comment to the question. I think the easiest and one liner which works for both Python2 and Python 3 will be

dict(zip(inv_map.values(), inv_map.keys()))

@Shb8086 2017-12-18 16:11:44

  def reverse_dictionary(input_dict):
      out = {}
      for v in input_dict.values():  
          for value in v:
              if value not in out:
                  out[value.lower()] = []

      for i in input_dict:
          for j in out:
              if j in map (lambda x : x.lower(),input_dict[i]):
                  out[j].append(i.lower())
                  out[j].sort()
      return out

this code do like this:

r = reverse_dictionary({'Accurate': ['exact', 'precise'], 'exact': ['precise'], 'astute': ['Smart', 'clever'], 'smart': ['clever', 'bright', 'talented']})

print(r)

{'precise': ['accurate', 'exact'], 'clever': ['astute', 'smart'], 'talented': ['smart'], 'bright': ['smart'], 'exact': ['accurate'], 'smart': ['astute']}

@Tom Aranda 2017-12-18 16:17:23

Generally, answers are much more helpful if they include an explanation of what the code is intended to do, and why that solves the problem without introducing others.

@Dr Beco 2018-07-14 16:06:56

It is a nice solution

@Liudvikas Akelis 2018-09-07 12:49:19

It's very nice, but a lot of unexplained decisions (for example, why lower case for keys?)

@user9918114 2018-06-09 12:20:42

This is not the best solution, but it works. Let's say the dictionary we want to reverse is:

dictionary = {'a': 1, 'b': 2, 'c': 3}, then:

dictionary = {'a': 1, 'b': 2, 'c': 3}
reverse_dictionary = {}
for index, val in enumerate(list(dictionary.values())):
    reverse_dictionary[val] = list(dictionary.keys())[index]

The output of reverse_dictionary, should be {1: 'a', 2: 'b', 3: 'c'}

@Miladiouss 2018-06-07 23:37:46

Inverse your dictionary:

dict_ = {"k0":"v0", "k1":"v1", "k2":"v1"}
inversed_dict_ = {val: key for key, val in dict_.items()}

print(inversed_dict_["v1"])

@SVJ 2018-04-19 03:24:11

Combination of list and dictionary comprehension. Can handle duplicate keys

{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}

@RVR 2017-08-30 10:11:43

def invertDictionary(d):
    myDict = {}
  for i in d:
     value = d.get(i)
     myDict.setdefault(value,[]).append(i)   
 return myDict
 print invertDictionary({'a':1, 'b':2, 'c':3 , 'd' : 1})

This will provide output as : {1: ['a', 'd'], 2: ['b'], 3: ['c']}

@genghiscrade 2017-04-26 14:28:34

I would do it that way in python 2.

inv_map = {my_map[x] : x for x in my_map}

@Amit Kushwaha 2017-04-03 05:39:53

Adding my 2 cents of pythonic way:

inv_map = dict(map(reversed, my_map.items()))

Example:

In [7]: my_map
Out[7]: {1: 'one', 2: 'two', 3: 'three'}

In [8]: inv_map = dict(map(reversed, my_map.items()))

In [9]: inv_map
Out[9]: {'one': 1, 'three': 3, 'two': 2}

@Adrian W 2018-09-20 10:01:32

This is a clone of Brendan Maguire's answer which has been given three years before.

@Ersatz Kwisatz 2017-01-25 20:23:49

This handles non-unique values and retains much of the look of the unique case.

inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}

For Python 3.x, replace itervalues with values. I can't take credit for this... it was suggested by Icon Jack.

@gabuzo 2017-10-24 08:21:37

This solution is quite elegant as a one liner and it manages the non unique values case. However it has a complexity in O(n2) which means it should be ok for several dozens of elements but it would be too slow for practical use if you have several hundreds of thousands of elements in your initial dictionary. The solutions based on a default dict are way faster than this one.

@Ersatz Kwisatz 2017-10-25 17:01:49

Gabuzo is quite right. This version is (arguably) clearer than some, but it is not suitable for large data.

@mveith 2017-01-10 10:37:35

If values aren't unique AND may be a hash (one dimension):

for k, v in myDict.items():
    if len(v) > 1:
        for item in v:
            invDict[item] = invDict.get(item, [])
            invDict[item].append(k)
    else:
        invDict[v] = invDict.get(v, [])
        invDict[v].append(k)

And with a recursion if you need to dig deeper then just one dimension:

def digList(lst):
    temp = []
    for item in lst:
        if type(item) is list:
            temp.append(digList(item))
        else:
            temp.append(item)
    return set(temp)

for k, v in myDict.items():
    if type(v) is list:
        items = digList(v)
        for item in items:
            invDict[item] = invDict.get(item, [])
            invDict[item].append(k)
    else:
        invDict[v] = invDict.get(v, [])
        invDict[v].append(k)

@gabuzo 2017-10-24 08:22:40

You might improve your solutions using a defaultdict: it'll remove all the invDict[item] = invDict.get(item, []) lines

@Brendan Maguire 2014-02-26 16:35:03

Another, more functional, way:

my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))

@Brian M. Hunt 2014-02-26 16:38:32

Thanks for posting. I am not sure this is preferable - to quote Guido Van Rossum in PEP 279: "filter and map should die and be subsumed into list comprehensions, not grow more variants".

@Brendan Maguire 2014-02-26 17:10:05

Yeah, that's a fair point Brian. I was just adding it as a point of conversation. The dict comprehension way is more readable for most I'd imagine. (And likely faster too I'd guess)

@dmvianna 2016-07-25 23:47:14

In Python 3 it should be my_map.items().

@Will S 2017-08-17 09:51:24

Might be less readable than others, but this way does have the benefit of being able to swap out dict with other mapping types such as collections.OrderedDict or collections.defaultdict

@irudyak 2016-12-26 23:01:25

We may also reverse a dictionary with duplicate keys using defaultdict:

from collections import Counter, defaultdict

def invert_dict(d):
    d_inv = defaultdict(list)
    for k, v in c.items():
        d_inv[v].append(k)
    return d_inv

text = 'aaa bbb ccc ddd aaa bbb ccc aaa' 
c = Counter(text.split()) # Counter({'aaa': 3, 'bbb': 2, 'ccc': 2, 'ddd': 1})
dict(invert_dict(c)) # {1: ['ddd'], 2: ['bbb', 'ccc'], 3: ['aaa']}  

See here:

This technique is simpler and faster than an equivalent technique using dict.setdefault().

@A-B-B 2012-10-24 20:40:19

This expands upon the answer Python reverse / invert a mapping, applying to when the values in the dict aren't unique.

class ReversibleDict(dict):

    def reversed(self):
        """
        Return a reversed dict, with common values in the original dict
        grouped into a list in the returned dict.

        Example:
        >>> d = ReversibleDict({'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2})
        >>> d.reversed()
        {1: ['d'], 2: ['c', 'b', 'f'], 3: ['a', 'e']}
        """

        revdict = {}
        for k, v in self.iteritems():
            revdict.setdefault(v, []).append(k)
        return revdict

The implementation is limited in that you cannot use reversed twice and get the original back. It is not symmetric as such. It is tested with Python 2.6. Here is a use case of how I am using to print the resultant dict.

If you'd rather use a set than a list, and there are applications for which this makes sense, instead of setdefault(v, []).append(k), use setdefault(v, set()).add(k).

@mueslo 2016-12-22 20:42:56

this would also be a good place to use sets instead of lists, i.e. revdict.setdefault(v, set()).add(k)

@mueslo 2016-12-22 20:57:39

Of course, but that's exacty why it's a good reason to use set. It's the intrinsic type that applies here. What if I want to find all keys where the values are not 1 or 2? Then I can just do d.keys() - inv_d[1] - inv_d[2] (in Python 3)

@SilentGhost 2009-01-27 15:24:56

For Python 2.7.x

inv_map = {v: k for k, v in my_map.iteritems()}

For Python 3+:

inv_map = {v: k for k, v in my_map.items()}

@Mike Fogel 2012-12-04 23:40:27

in python2.7+, using map.iteritems() would be more efficient.

@Rick Teachey 2016-08-21 13:03:35

however in python 3+ just use my_map.items() as the answer shows.

@rasen58 2016-09-08 13:42:08

This reverses the list as well. i.e. { 'a': 1, 'b':2 } returns { 2: 'b', 1:'a' } instead of just inverting without reversing

@rasen58 2016-09-08 13:47:32

This is because .items() doesn't return a sorted sequence

@Anentropic 2016-10-27 12:42:19

@rasen58 Python dictionaries don't have an ordering

@tgy 2017-02-28 12:55:51

In recent Python 2.7.x versions my_map.items() works as well

@Arya McCarthy 2017-06-01 22:29:06

@valentin Yes, that works, but it's less efficient because it generates a list of pairs, rather than an iterator.

@gabuzo 2017-10-23 16:28:44

This'll work except that it won't work if there is not unicity in the values. In that case you'll loose some entries

@Mattias 2018-08-26 17:44:53

Yes, as a implementation detail. The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon. There is no guarantee it will stay that way so don't write code relying on Dict having the same behavior as OrderedDict.

@interDist 2018-10-30 10:27:44

@Mattias, this is true for Python 3.6. For version 3.7 the order-preserving is official: mail.python.org/pipermail/python-dev/2017-December/151283.ht‌​ml. BDFL said so.

@Kwaw Annor 2016-09-11 22:26:46

Using zip

inv_map = dict(zip(my_map.values(), my_map.keys()))

@dhvlnyk 2014-07-25 09:31:58

Try this for python 2.7/3.x

inv_map={};
for i in my_map:
    inv_map[my_map[i]]=i    
print inv_map

@beco 2010-11-01 17:55:53

For all kinds of dictionary, no matter if they don't have unique values to use as keys, you can create a list of keys for each value

inv_map = {v: inv_map.get(v, []) + [k] for k,v in my_map.items()}

@Matthias 009 2012-05-01 16:36:49

have you tested it for non-unique values? e.g. map = { 'a': 1, 'b':2, 'c':1 } gives {1: ['c'], 2: ['b']} for inv_map, 'a' gets lost (I put inv_map = {} before your line)

@Eric 2014-07-30 15:11:33

This doesn't work, because the new value of inv_map is not assigned until the comprehension completes

@pcv 2010-04-17 20:14:06

If the values aren't unique, and you're a little hardcore:

inv_map = dict(
    (v, [k for (k, xx) in filter(lambda (key, value): value == v, my_map.items())]) 
    for v in set(my_map.values())
)

Especially for a large dict, note that this solution is far less efficient than the answer Python reverse / invert a mapping because it loops over items() multiple times.

@Russ Bradberry 2012-10-03 19:19:56

This is just plain unreadable and a good example of how to not write maintainable code. I won't -1 because it still answers the question, just my opinion.

@Robert Rossney 2009-01-27 21:33:26

If the values in my_map aren't unique:

inv_map = {}
for k, v in my_map.iteritems():
    inv_map[v] = inv_map.get(v, [])
    inv_map[v].append(k)

@alsuren 2010-11-10 14:55:31

... or just inv_map.setdefault(v, []).append(k). I used to be a defaultdict fanboy, but then I got screwed one too many times and concluded that actually explicit is better than implicit.

@Yaroslav Bulatov 2016-04-22 20:37:27

This answer is incorrect for multi-map, append here is useless because the value is reset to empty list each time, should use set_default

@Mark Amery 2016-07-16 17:23:51

@YaroslavBulatov no, the code as shown here isn't broken - inv_map.get(v, []) returns the already-added list if there is one, so the assignment doesn't reset to an empty list. setdefault would still be prettier, though.

@Artyer 2017-08-11 17:17:09

A set would make more sense here. The keys are (probably) hashable, and there is no order. inv_map.setdefault(v, set()).add(k).

@unbeknown 2009-01-27 14:50:22

Assuming that the values in the dict are unique:

dict((v, k) for k, v in my_map.iteritems())

@Buttons840 2012-04-27 20:34:02

What if the values aren't unique?

@John La Rooy 2012-05-24 01:52:49

The values have to be hashable too

@Wrzlprmft 2014-10-25 14:13:21

@Buttons840: If the values aren’t unique, there is no unique inversion of the dictionary anyway or, with other words, inverting does not make sense.

@Evgeni Sergeev 2015-04-21 08:13:02

@Buttons840 Only the last key will appear for the value. There are probably no guarantees on the order that iteritems() will output, so it may be assumed that an arbitrary key will be assigned for a non-unique value, in a way that will be apparently reproducible under some conditions, but no so in general.

@Mark Amery 2016-07-16 17:17:33

Note, of course, that in Python 3 there is no longer an iteritems() method and this approach will not work; use items() there instead as shown in the accepted answer. Also, a dictionary comprehension would make this prettier than calling dict.

@Leo 2016-10-25 19:08:21

@Wrzlprmft There is a natural definition for inverse in the case of non unique values. Every value is mapped to the set of keys leading to it.

@sykora 2009-01-27 14:49:46

Try this:

inv_map = dict(zip(my_map.values(), my_map.keys()))

(Note that the Python docs on dictionary views explicitly guarantee that .keys() and .values() have their elements in the same order, which allows the approach above to work.)

Alternatively:

inv_map = dict((my_map[k], k) for k in my_map)

or using python 3.0's dict comprehensions

inv_map = {my_map[k] : k for k in my_map}

@gented 2018-06-22 08:26:10

Notice that this only works if the keys are unique (which is almost never the case if you want to invert them).

@Kawu 2018-10-27 01:03:03

According to python.org/dev/peps/pep-0274 dict comprehensions are available in 2.7+, too.

@Taras Voitovych 2016-08-05 19:47:24

I wrote this with the help of cycle 'for' and method '.get()' and I changed the name 'map' of the dictionary to 'map1' because 'map' is a function.

def dict_invert(map1):
    inv_map = {} # new dictionary
    for key in map1.keys():
        inv_map[map1.get(key)] = key
    return inv_map

@thodnev 2016-08-02 18:08:53

Not something completely different, just a bit rewritten recipe from Cookbook. It's futhermore optimized by retaining setdefault method, instead of each time getting it through the instance:

def inverse(mapping):
    '''
    A function to inverse mapping, collecting keys with simillar values
    in list. Careful to retain original type and to be fast.
    >> d = dict(a=1, b=2, c=1, d=3, e=2, f=1, g=5, h=2)
    >> inverse(d)
    {1: ['f', 'c', 'a'], 2: ['h', 'b', 'e'], 3: ['d'], 5: ['g']}
    '''
    res = {}
    setdef = res.setdefault
    for key, value in mapping.items():
        setdef(value, []).append(key)
    return res if mapping.__class__==dict else mapping.__class__(res)

Designed to be run under CPython 3.x, for 2.x replace mapping.items() with mapping.iteritems()

On my machine runs a bit faster, than other examples here

@cjay 2014-03-06 20:50:11

Fast functional solution for non-bijective maps (values not unique):

from itertools import imap, groupby

def fst(s):
    return s[0]

def snd(s):
    return s[1]

def inverseDict(d):
    """
    input d: a -> b
    output : b -> set(a)
    """
    return {
        v : set(imap(fst, kv_iter))
        for (v, kv_iter) in groupby(
            sorted(d.iteritems(),
                   key=snd),
            key=snd
        )
    }

In theory this should be faster than adding to the set (or appending to the list) one by one like in the imperative solution.

Unfortunately the values have to be sortable, the sorting is required by groupby.

@Mark Amery 2016-07-16 18:17:13

"In theory this should be faster than adding to the set (or appending to the list) one by one" - no. Given n elements in the original dict, your approach has O(n log n) time complexity due to the need to sort the dict's items, whereas the naive imperative approach has O(n) time complexity. For all I know your approach may be faster up until absurdly large dicts in practice, but it certainly isn't faster in theory.

@EyoelD 2016-01-09 01:26:12

Since dictionaries require one unique key within the dictionary unlike values, we have to append the reversed values into a list of sort to be included within the new specific keys.

def r_maping(dictionary):
    List_z=[]
    Map= {}
    for z, x in dictionary.iteritems(): #iterate through the keys and values
        Map.setdefault(x,List_z).append(z) #Setdefault is the same as dict[key]=default."The method returns the key value available in the dictionary and if given key is not available then it will return provided default value. Afterward, we will append into the default list our new values for the specific key.
    return Map

@seiferas 2015-11-24 18:17:03

if the items are not unique try this:

     dict={}
     dict1={}
     num=int(raw_input(" how many numbers in dict?--> "))
     for i in range (0,num):
         key=raw_input(" enter key --> ")
         value=raw_input("enter value --> ")
         dict[key]=value
     keys=dict.keys()
     values=dict.values()
     for b in range (0,num):
         keys[b],values[b]=values[b],keys[b]
         dict1[keys[b]]=values[b]
     print keys
     print values
     print dict1

@Tempux 2015-11-24 18:23:04

This question has been asked 6 years ago and has been answered. Please Answer recent questions or if you want to answer old questions make sure your answer offers something important.

@NcAdams 2014-09-28 06:50:44

I think the best way to do this is to define a class. Here is an implementation of a "symmetric dictionary":

class SymDict:
    def __init__(self):
        self.aToB = {}
        self.bToA = {}

    def assocAB(self, a, b):
        # Stores and returns a tuple (a,b) of overwritten bindings
        currB = None
        if a in self.aToB: currB = self.bToA[a]
        currA = None
        if b in self.bToA: currA = self.aToB[b]

        self.aToB[a] = b
        self.bToA[b] = a
        return (currA, currB)

    def lookupA(self, a):
        if a in self.aToB:
            return self.aToB[a]
        return None

    def lookupB(self, b):
        if b in self.bToA:
            return self.bToA[b]
        return None

Deletion and iteration methods are easy enough to implement if they're needed.

This implementation is way more efficient than inverting an entire dictionary (which seems to be the most popular solution on this page). Not to mention, you can add or remove values from your SymDict as much as you want, and your inverse-dictionary will always stay valid -- this isn't true if you simply reverse the entire dictionary once.

@Brian M. Hunt 2014-09-28 10:59:58

I like this idea, though it would be good to note that it trades off additional memory to achieve improved computation. A happier medium may be caching or lazily computing the mirror. It is also worth noting that it could be made more syntactically appealing with e.g. dictionary views and custom operators.

@NcAdams 2014-09-28 20:46:01

@BrianM.Hunt It trades off memory, but not a lot. You only store two sets of pointers to each object. If your objects are much bigger than single integers, this won't make much of a difference. If you have huge table of tiny objects on the other hand, you might need to consider those suggestions...

@NcAdams 2014-09-28 20:47:00

And I agree, there's more to be done here -- I might flesh this out into a fully functioning datatype later

@Mark Amery 2016-07-16 18:11:03

"This implementation is way more efficient than inverting an entire dictionary" - um, why? I don't see any plausible way this approach can have a significant performance benefit; you've still got two dictionaries this way. If anything, I'd expect this to be slower than, say, inverting the dict with a comprehension, because if you invert the dict Python can plausibly know in advance how many buckets to allocate in the underlying C data structure and create the inverse map without ever calling dictresize, but this approach denies Python that possibility.

@Alf 2014-09-24 12:23:00

Function is symmetric for values of type list; Tuples are coverted to lists when performing reverse_dict(reverse_dict(dictionary))

def reverse_dict(dictionary):
    reverse_dict = {}
    for key, value in dictionary.iteritems():
        if not isinstance(value, (list, tuple)):
            value = [value]
        for val in value:
            reverse_dict[val] = reverse_dict.get(val, [])
            reverse_dict[val].append(key)
    for key, value in reverse_dict.iteritems():
        if len(value) == 1:
            reverse_dict[key] = value[0]
    return reverse_dict

@RussellStewart 2013-04-09 19:20:58

In addition to the other functions suggested above, if you like lambdas:

invert = lambda mydict: {v:k for k, v in mydict.items()}

Or, you could do it this way too:

invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )

@Mark Amery 2016-07-16 18:03:08

-1; all you've done is taken other answers from the page and put them into a lambda. Also, assigning a lambda to a variable is a PEP 8 violation.

Related Questions

Sponsored Content

27 Answered Questions

29 Answered Questions

[SOLVED] Finding the index of an item given a list containing it in Python

  • 2008-10-07 01:39:38
  • Eugene M
  • 3150767 View
  • 2595 Score
  • 29 Answer
  • Tags:   python list

38 Answered Questions

[SOLVED] How do I efficiently iterate over each entry in a Java Map?

25 Answered Questions

[SOLVED] How can I safely create a nested directory in Python?

15 Answered Questions

[SOLVED] What are metaclasses in Python?

23 Answered Questions

[SOLVED] What is the difference between @staticmethod and @classmethod?

22 Answered Questions

[SOLVED] Reverse a string in Python

  • 2009-05-31 02:10:10
  • oneself
  • 1165381 View
  • 1208 Score
  • 22 Answer
  • Tags:   python string

17 Answered Questions

[SOLVED] Does Python have a string 'contains' substring method?

55 Answered Questions

[SOLVED] Calling an external command in Python

49 Answered Questions

[SOLVED] Sort a Map<Key, Value> by values

Sponsored Content