148

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?

Timur Shtatland
  • 12,024
  • 2
  • 30
  • 47
Roee Adler
  • 33,434
  • 32
  • 105
  • 133
  • 1
    See http://stackoverflow.com/questions/1087694/how-to-swap-keys-for-values-in-a-dictionary for an identical question that has a nice answer if you're using Python 3 – Stephen Edmonds Sep 24 '09 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... – Roee Adler Sep 25 '09 at 05: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. – o0'. Oct 20 '11 at 12:55

19 Answers19

201

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())
gorcajo
  • 561
  • 1
  • 6
  • 11
liori
  • 40,917
  • 13
  • 78
  • 105
  • 17
    While this seems to be correct, its really good to add an explanation of how it works rather than just the code. – Will Sep 10 '15 at 19:49
  • 6
    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'} – Hanan Shteingart Aug 03 '17 at 22:44
  • 5
    @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). – liori Aug 04 '17 at 09:17
  • the python2 code works... but the list comprehension is missing the `[` and `]`. does a list comprehension not require the `[` and `]`? – Trevor Boyd Smith Nov 29 '18 at 17:37
  • @TrevorBoydSmith: this is not list comprehension, this is a [generator expression](https://www.python.org/dev/peps/pep-0289/). – liori Nov 29 '18 at 19:14
  • 1
    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. – AlexD Feb 06 '20 at 18:28
  • okay . Is there a way to do it without having to create memory for `res` ? .Like using the original dictionary only to store the interchanged values – Jdeep Jul 09 '20 at 08:33
  • @HananShteingart , If you have got any answer by asking the question , can you share the link? – Jdeep Jul 09 '20 at 08:36
65
new_dict = dict(zip(my_dict.values(), my_dict.keys()))
vvvvv
  • 25,404
  • 19
  • 49
  • 81
Javier
  • 60,510
  • 8
  • 78
  • 126
  • 8
    Are really values() and keys() guaranteed to have the same ordering? – Lennart Regebro Jul 06 '09 at 16:28
  • 2
    yes, from http://www.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. – sunqiang Jul 06 '09 at 16:39
  • 5
    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 Jul 07 '09 at 17:59
  • @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 – Javier Jul 07 '09 at 19:26
  • @CarlMeyer additionally for n > 1e6 (or 1e9) the memory usage will also be really large... and also slow this down a bunch. – Trevor Boyd Smith Nov 29 '18 at 17:39
  • @TrevorBoydSmith: On Python 3, `.values()` and `.keys()` are views of the backing `dict` and `zip` is a lazy iterator; there's no extra copies being made (aside from the desired new `dict`). On Python 2 (if you're still using it) using `.itervalues()` and `.iterkeys()` (or just omitting `.keys()` entirely, since `dict` are already iterables of their keys) and using `itertools.izip` instead of `zip` would avoid the temporaries (e.g. `dict(itertools.izip(my_dict.itervalues(), my_dict))` would involve no meaningful memory overhead from temporaries). – ShadowRanger Mar 17 '22 at 19:35
  • @ShadowRanger if the code is from python2 then my statement is correct and there would be lots of memory usage. at the time of my comment i was still using python2 so i assumed python2. if the code is from python3 then you are definitely correct. good job. – Trevor Boyd Smith Mar 18 '22 at 18:40
61

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'}
airstrike
  • 2,270
  • 1
  • 25
  • 26
SilentGhost
  • 307,395
  • 66
  • 306
  • 293
35

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.

questionto42
  • 7,175
  • 4
  • 57
  • 90
Akavall
  • 82,592
  • 51
  • 207
  • 251
34
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'}
questionto42
  • 7,175
  • 4
  • 57
  • 90
sunqiang
  • 6,422
  • 1
  • 32
  • 32
  • 3
    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 Jul 06 '09 at 15:49
  • 2
    @Andre Miller: It takes the last occurrence of the particular key: dict(((1,3),(1,2))) == {1:2} – balpha Jul 06 '09 at 15:51
  • 2
    duplicates will get overwritten with the last encountered dupe. – Christopher Jul 06 '09 at 15:52
  • 2
    @Andre Miller: And because d.items() returns items in an arbitrary order you get an arbitrary key for duplicate values. – Ants Aasma Jul 06 '09 at 15:53
  • 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. – riza Jul 06 '09 at 15:53
  • @Andre, I think the later will remove the prior key out of dict for example {'x':1, 'y':2, 'z':2} -> {1: 'x', 2: 'z'} but the order is not always intuitive – sunqiang Jul 06 '09 at 15:54
  • isn't this the same answer as https://stackoverflow.com/a/1031878/52074 ... – Trevor Boyd Smith Nov 29 '18 at 17:41
  • @TrevorBoydSmith from the post time, maybe I need a time machine to avoid this.:) – sunqiang Dec 04 '18 at 00:48
24

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
giotto
  • 532
  • 3
  • 15
Hanan Shteingart
  • 8,480
  • 10
  • 53
  • 66
19

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

pkit
  • 7,993
  • 6
  • 36
  • 36
  • 4
    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 Jun 23 '09 at 11:01
  • 21
    @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: http://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." – nosklo Jun 23 '09 at 11:12
  • 1
    Ok, then I am wrong... I haven't checked the online docs. Thank you for pointing this. – liori Jun 23 '09 at 11:16
  • You could use the iterator itertools.izip instead of zip to make this answer more efficient. – Alasdair Jun 23 '09 at 11:17
  • And iterkeys and itervalues. But could just as well use iteritems() – nosklo Jun 23 '09 at 11:31
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.

questionto42
  • 7,175
  • 4
  • 57
  • 90
Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • 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! – monojohnny Apr 06 '11 at 18:45
16

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.

Sunny Patel
  • 7,830
  • 2
  • 31
  • 46
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}
balpha
  • 50,022
  • 18
  • 110
  • 131
  • 3
    Actually Dict Comprehensions ([PEP 274](http://www.python.org/dev/peps/pep-0274/)) work with Python 2.7 as well. – Arseny Nov 11 '13 at 10:53
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'
Sparkup
  • 3,686
  • 2
  • 36
  • 50
shadow2097
  • 71
  • 1
  • 3
6

Can be done easily with dictionary comprehension:

{d[i]:i for i in d}
juzraai
  • 5,693
  • 8
  • 33
  • 47
user10084443
  • 151
  • 2
  • 1
  • Succinct. The the new dict behaves in a manner that makes the old values unique keys in the new meaning values may be lost. – Rich Andrews Sep 23 '21 at 15:19
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.

Will
  • 24,082
  • 14
  • 97
  • 108
Ilya Prokin
  • 684
  • 6
  • 11
  • .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. – Ilya Prokin Sep 10 '15 at 19:27
2

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]}
pegah
  • 791
  • 8
  • 15
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
Devesh Saini
  • 557
  • 5
  • 16
  • `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():` – ShadowRanger Mar 17 '22 at 19:43
1

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

res = dict((v,k) for k,v in a.items())
Gravity Grave
  • 2,802
  • 1
  • 27
  • 39
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.

timgeb
  • 76,762
  • 20
  • 123
  • 145
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}

AlketCecaj
  • 117
  • 1
  • 11
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.

LuWil
  • 46
  • 3
  • 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 Mar 17 '22 at 19:46
  • 1
    @ShadowRanger Thank you for pointing this out. It should have been mentioned along with the lack of readability. – LuWil Mar 20 '22 at 00:41