163

I receive a dictionary as input, and would like to to return a dictionary whose keys will be the input's values and whose value will be the corresponding input keys. Values are unique.

For example, say my input is:

a = dict() a['one']=1 a['two']=2 

I would like my output to be:

{1: 'one', 2: 'two'} 

To clarify I would like my result to be the equivalent of the following:

res = dict() res[1] = 'one' res[2] = 'two' 

Any neat Pythonic way to achieve this?

4
  • 1
    See stackoverflow.com/questions/1087694/… for an identical question that has a nice answer if you're using Python 3 Commented Sep 24, 2009 at 12:48
  • @Stephen: see the second most voted answer, it's the same as the accepted one in the question you linked to. The crowd preferred the other answer though... Commented Sep 25, 2009 at 5:36
  • 5
    Python is not perl, python is not ruby. Readability counts. Sparse is better than dense. Given this, all the methods of these answers are just bad™; the one in the question is the best way to go. Commented Oct 20, 2011 at 12:55
  • This is a pretty popular question. So I decided to profile different approaches. You can see the results here Commented Dec 19, 2024 at 9:13

19 Answers 19

219

Python 2:

res = dict((v,k) for k,v in a.iteritems()) 

Python 3 (thanks to @erik):

res = dict((v,k) for k,v in a.items()) 
Sign up to request clarification or add additional context in comments.

8 Comments

While this seems to be correct, its really good to add an explanation of how it works rather than just the code.
What if values are not unique? Then the keys should be a list... for example: d = {'a':3, 'b': 2, 'c': 2} {v:k for k,v in d.iteritems()} {2: 'b', 3: 'a'} should be {2: ['b','c'], 3: 'a'}
@HananShteingart: the OP's question stated values are unique. Please create a separate question post for your case (and preferably link it here for other people).
the python2 code works... but the list comprehension is missing the [ and ]. does a list comprehension not require the [ and ]?
Two things: 1) if your original has a repeated value, it will overwrite the previous and you will will end up with a shorter dictionary; 2) if "value" is not hashable -such as an array-, it will fail.
|
69
new_dict = dict(zip(my_dict.values(), my_dict.keys())) 

7 Comments

Are really values() and keys() guaranteed to have the same ordering?
yes, from python.org/dev/peps/pep-3106 The specification implies that the order in which items are returned by .keys(), .values() and .items() is the same (just as it was in Python 2.x), because the order is all derived from the dict iterator (which is presumably arbitrary but stable as long as a dict isn't modified). but this answer needs call my_dict twice(one for values, one for keys). maybe this is not ideal.
Yes, this answer iterates through the dict twice. sunqiang's answer is preferable for a large dictionary as it only requires one iteration.
@Carl Meyer: agree, also, he's using itertools which are a lot better for big datasets. although i wonder if the final dict() call is also streaming, or if it first assembles the whole pairs list
@CarlMeyer additionally for n > 1e6 (or 1e9) the memory usage will also be really large... and also slow this down a bunch.
|
68

From Python 2.7 on, including 3.0+, there's an arguably shorter, more readable version:

>>> my_dict = {'x':1, 'y':2, 'z':3} >>> {v: k for k, v in my_dict.items()} {1: 'x', 2: 'y', 3: 'z'} 

Comments

41

You can make use of dict comprehensions:

Python 3

res = {v: k for k, v in a.items()} 

Python 2

res = {v: k for k, v in a.iteritems()} 

Edited: For Python 3, use a.items() instead of a.iteritems(). Discussions about the differences between them can be found in iteritems in Python on SO.

Comments

36
In [1]: my_dict = {'x':1, 'y':2, 'z':3} 

Python 3

In [2]: dict((value, key) for key, value in my_dict.items()) Out[2]: {1: 'x', 2: 'y', 3: 'z'} 

Python 2

In [2]: dict((value, key) for key, value in my_dict.iteritems()) Out[2]: {1: 'x', 2: 'y', 3: 'z'} 

8 Comments

Not in the original question, I'm just curious what will happen if you had duplicate values in the original dictionary and then swap key/values with this method?
@Andre Miller: It takes the last occurrence of the particular key: dict(((1,3),(1,2))) == {1:2}
duplicates will get overwritten with the last encountered dupe.
@Andre Miller: And because d.items() returns items in an arbitrary order you get an arbitrary key for duplicate values.
I think that it will takes the last key, value pair that it found. It's like a['x'] = 3. Then you set a['x'] = 4.
|
25

The current leading answer assumes values are unique which is not always the case. What if values are not unique? You will loose information! For example:

d = {'a':3, 'b': 2, 'c': 2} {v:k for k,v in d.iteritems()} 

returns {2: 'b', 3: 'a'}.

The information about 'c' was completely ignored. Ideally it should had be something like {2: ['b','c'], 3: ['a']}. This is what the bottom implementation does.

Python 2.x

def reverse_non_unique_mapping(d): dinv = {} for k, v in d.iteritems(): if v in dinv: dinv[v].append(k) else: dinv[v] = [k] return dinv 

Python 3.x

def reverse_non_unique_mapping(d): dinv = {} for k, v in d.items(): if v in dinv: dinv[v].append(k) else: dinv[v] = [k] return dinv 

2 Comments

this should be the correct answer since it covers a more general case
Thank you for this! I was losing information with the other solutions.
19

You could try:

Python 3

d={'one':1,'two':2} d2=dict((value,key) for key,value in d.items()) d2 {'two': 2, 'one': 1} 

Python 2

d={'one':1,'two':2} d2=dict((value,key) for key,value in d.iteritems()) d2 {'two': 2, 'one': 1} 

Beware that you cannot 'reverse' a dictionary if

  1. More than one key shares the same value. For example {'one':1,'two':1}. The new dictionary can only have one item with key 1.
  2. One or more of the values is unhashable. For example {'one':[1]}. [1] is a valid value but not a valid key.

See this thread on the python mailing list for a discussion on the subject.

1 Comment

Also +1 about the note about making sure the values in the original dict are unique ; otherwise you'll get overwrites in the 'reversed' dict...and this (I just found this to my cost) can cause tricky bugs in your code!
18

res = dict(zip(a.values(), a.keys()))

5 Comments

dict does not guarantee that its values() and keys() will return elements in the same order. Also, keys(), values() and zip() return a list, where an iterator would be sufficient.
@liori: You're wrong. dict guarantees that its values() and keys() WILL be on the same order, if you don't modify the dict between calls to values() and keys() of course. The documentation states that here: (read the "Note" part: docs.python.org/library/stdtypes.html#dict.items) "If items(), keys(), values(), iteritems(), iterkeys(), and itervalues() are called with no intervening modifications to the dictionary, the lists will directly correspond."
Ok, then I am wrong... I haven't checked the online docs. Thank you for pointing this.
You could use the iterator itertools.izip instead of zip to make this answer more efficient.
And iterkeys and itervalues. But could just as well use iteritems()
17

Another way to expand on Ilya Prokin's response is to actually use the reversed function.

dict(map(reversed, my_dict.items())) 

In essence, your dictionary is iterated through (using .items()) where each item is a key/value pair, and those items are swapped with the reversed function. When this is passed to the dict constructor, it turns them into value/key pairs which is what you want.

Comments

15
new_dict = dict( (my_dict[k], k) for k in my_dict) 

or even better, but only works in Python 3:

new_dict = { my_dict[k]: k for k in my_dict} 

1 Comment

Actually Dict Comprehensions (PEP 274) work with Python 2.7 as well.
7

Suggestion for an improvement for Javier answer :

dict(zip(d.values(),d)) 

Instead of d.keys() you can write just d, because if you go through dictionary with an iterator, it will return the keys of the relevant dictionary.

Ex. for this behavior :

d = {'a':1,'b':2} for k in d: k 'a' 'b' 

Comments

6

Can be done easily with dictionary comprehension:

{d[i]:i for i in d} 

1 Comment

Succinct. The the new dict behaves in a manner that makes the old values unique keys in the new meaning values may be lost.
4

Hanan's answer is the correct one as it covers more general case (the other answers are kind of misleading for someone unaware of the duplicate situation). An improvement to Hanan's answer is using setdefault:

mydict = {1:a, 2:a, 3:b} result = {} for i in mydict: result.setdefault(mydict[i],[]).append(i) print(result) >>> result = {a:[1,2], b:[3]} 

Comments

3
dict(map(lambda x: x[::-1], YourDict.items())) 

.items() returns a list of tuples of (key, value). map() goes through elements of the list and applies lambda x:[::-1] to each its element (tuple) to reverse it, so each tuple becomes (value, key) in the new list spitted out of map. Finally, dict() makes a dict from the new list.

1 Comment

.items() returns a list of tuples (key, value). map() goes through elements of the list and applies lambda x:[::-1] to each its element (tuple) to reverse it, so each tuple becomes (value, key) in the new list spitted out of map. Finally, dict() makes a dict from the new list.
1

Using loop:-

newdict = {} #Will contain reversed key:value pairs. for key, value in zip(my_dict.keys(), my_dict.values()): # Operations on key/value can also be performed. newdict[value] = key 

1 Comment

for key, value in zip(my_dict.keys(), my_dict.values()): is a slow/needlessly complicated way to spell for key, value in my_dict.items():
1

If you're using Python3, it's slightly different:

res = dict((v,k) for k,v in a.items()) 

Comments

1

Adding an in-place solution:

>>> d = {1: 'one', 2: 'two', 3: 'three', 4: 'four'} >>> for k in list(d.keys()): ... d[d.pop(k)] = k ... >>> d {'two': 2, 'one': 1, 'four': 4, 'three': 3} 

In Python3, it is critical that you use list(d.keys()) because dict.keys returns a view of the keys. If you are using Python2, d.keys() is enough.

Comments

1

I find this version the most comprehensive one:

a = {1: 'one', 2: 'two'}

swapped_a = {value : key for key, value in a.items()}

print(swapped_a)

output : {'one': 1, 'two': 2}

Comments

0

An alternative that is not quite as readable (in my opinion) as some of the other answers:

new_dict = dict(zip(*list(zip(*old_dict.items()))[::-1]))

where list(zip(*old_dict.items()))[::-1] gives a list of 2 tuples, old_dict's values and keys, respectively.

2 Comments

This is clever (in the sense of "clever for the sake of being clever, but never actually do it"), but just to note, it has huge temporaries (it has to completely unpack all the pairs to pass to zip at once before zip can produce any outputs, then has to listify the zip, then reverse it, all producing large temporaries). Amusing though.
@ShadowRanger Thank you for pointing this out. It should have been mentioned along with the lack of readability.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.