How to Switch Keys and Values in a Python Dictionary?

Problem: Given a dictionary in Python; how to switch Keys and Values? 

Summary: Use one of the following methods to switch between the keys and values in a dictionary with unique values.

Imagine you in the morning, on your desktop, with your coffee and your laptop in front of you. You feel relaxed, comfortable, sure about yourself and ready for another amazing day doing what you love the most. To solve problems with your brain and your fingers using the potential that Python offers to you!

Then your boss arrives and looking into your eyes he says: “Look, we have a problem and I need you to fix it. You have 1 hour to give me a solution that we can replicate for all the files we have in the company or we are all fired”

Your boss is a nice person. He gives you this example to start with: 

# Input 🡪     {'a': 1, 'b': 2, 'c': 3, 'd': 4}
# Output 🡪    {1: 'a', 2: 'b', 3: 'c', 4: 'd'}

In this article, we will show you four methods to accomplish this. The most Pythonic one is Method 4—so, if you’re short on time, go to Method 4 right away!

Background

If you are an experienced Python developer, you probably have a solid base of all kind of data structures. If so, just skip ahead and go to Method 1. On the other hand, if you are new to this topic or you want to refresh this data type, I invite you to read these lines below. As a Python developer, it is important to gain knowledge and build a solid foundation in data structures

In this article we are going to talk about how to revert one of the most useful structures any Python developer has to master, this is the dictionary

But what is it a dictionary?

A dictionary is a data structure formed by a set of key : value pairs. 

The syntax is:

{'key1': 'value1', 'key2': 'value2', 'key3': 'value3',}

It also can be represented like this for easy reading:

{
    'key1': 'value1', 
    'key2': 'value2', 
    'key3': 'value3',
}

Note: The last comma after value3 it is not necessary, indeed. But I recommend you to get this it as a habit and write it always. It will save you time by avoiding unwanted bugs in your future clean code 🙂 .

The key can be any kind of type, but what is important to highlight here is that:

  • The key has to be Unique in the whole dictionary. If not the last duplicated key will override the defined previous one

Example of a dictionary with an integer as a key:

{1: 100, 2: 200}

Example of a dictionary with a float as a key:

{1.0: 100, 2.3: 200}

Example of a dictionary with string as a key:

{'a': 100, 'b': 200}

Example of a dictionary with a tuple as a key:

{(0, 0): 100, (1, 1): 200}
 
#or
 
{('Harry','Potter') : 100, ('Hermione','Granger') : 200}

Note: Although you can use a float as a key, it is not very recommendable because if you define 1.0 and 1 the last key will override the first key.

Here you have an example:

{ 1.0: 100, 1: 200} 🡪 {1.0: 200}

Method 1: Using a for loop approach

The easiest solution and the typical one that any developer may discover at first would be to use the structure “for loop” to perform a definite iteration to accomplish the task.

The python for loop is represented by a variable, an iterable, and some statements. 

The syntax is: 

for <var> in <iterable>:
    <statement(s)>

Knowing this structure we could have a first valid approach to the solution: 

my_dict = {'a': 1, 'c': 3, 'b': 2, 'd': 4}
new_dict = {}
for k, v in my_dict.items():
    new_dict[v] = k

Output:

{1: 'a', 2: 'b', 3: 'c', 4: 'd'}

Explanation:

  1. In the above code, we need to create a new instance of a dictionary using the expression {} and assigned it to a new variable called new_dict
new_dict = {}
  1. Then we use the “for loop” to iterate the keys and values of the dictionary.
  1. k,v are the variables. The key and values
  2. my_dict is the iterable data structure that can be a dictionary, a list, or a tuple. In this case, we need to add the method .items() that returns a list of (key, value) tuple pairs. my_dict.items returns:
    dict_items([('a', 1), ('b', 2), ('c', 3)])
  1. new_dict[v] = k is the statement where we switch the values of the dictionary. 

Method 2: Using the zip function

Another possible solution would be using the zip function. 

The syntax is:

zip(*iterables)

But how does it work?

Well, the zip function returns an object created from some iterators given as parameters. These iterators can be lists, but they must have the same number of items each. This is to assure the proper join between the items. Here you can see an example:

#iterable 1 = ['one', 'two', 'three']
#iterable  = [1, 2, 3]
 
zip(['one', 'two', 'three'], [1, 2, 3])
 
#result: [('one', 1), ('two', 2), ('three', 3)]

So at this point, the solution for the second method would be:

my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
 
dict(zip(my_map.values(), my_map.keys()))

Output:

{1: 'a', 2: 'b', 3: 'c', 4: 'd'}

Explanation:

The idea behind this solution is to provide to the zip function 2 iterables, actually 2 lists, in this case, to create a unique list of tuples. The trick here is to use the keys as values and vice versa by using the form my_dict.values() to obtain the values and my_dict.keys() to obtain the keys in two separated lists. 

my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

my_dict.values()
# [1, 2, 3, 4] 

my_dict.keys()
# ['a', 'c', 'c', 'd']
  1. Once this is accomplished if we use the zip function we will have:
zip(my_map.values(), my_map.keys())
# [(1, 'a'), (2, 'b'), (3, 'c'),  (4, 'd')]
  1. At this point the only we need to create a dictionary using the type constructor dict() and obtaining the result we were looking for:
dict(zip(my_map.values(), my_map.keys()))

Method 3: Using the map and reverse functions 

The third solution you can think of is using the map and reverse function together with the constructor dict().

But how does it work and how do we use these two functions exactly? Let’s have a look at them both to understand it.

Reversed Function:

The reversed function has the property to return an iterator in the reversed order of a sequence given. It is important to mark that reversed() just accepts sequences and not any other kind of iterators. So in case you want to reverse an iterator you should consider to transform it previously to a list.  

The syntax is:

reversed(seq)

Examples:

string sequence: 

seq = 'retxnif'

reversed(seq)
# <reversed object at 0x0000000002A41AC8>

list(reversed(seq)) 
# ['f', 'i', 'n', 'x', 't', 'e', 'r']

list sequence:

seq = ['r', 'e', 't', 'x', 'n', 'i', 'f']

reversed(seq)
# <listreverseiterator object at 0x0000000002A41AC8>

list(reversed(seq))
# ['f', 'i', 'n', 'x', 't', 'e', 'r'] 

tuple sequence:

seq = ('r', 'e', 't', 'x', 'n', 'i', 'f')

reversed(seq)
# <reversed object at 0x0000000002AB2C48>

list(reversed(seq))
# ['f', 'i', 'n', 'x', 't', 'e', 'r']

range sequence

seq = range(5)
#  [0, 1, 2, 3, 4]

reversed(seq) 
# <listreverseiterator object at 0x0000000002A41AC8>

list(reversed(seq))
# [4, 3, 2, 1, 0]

Probably if you have read the Coffee Break Python Slicing from Chris you would notice that the last case could be achieved by range(5)[::-1]. However, it seems from the documentation that reversed(seq) is faster and use less memory. So keep it in mind.

Map Function

To comprehend the map function, first, we need to understand what mapping means. When we use the map, what we are after is to produce a new iterable from the original one by applying a transformational function to each item of it. 

In other words, is a way to process iterables without the need of a loop

The syntax is:

map(function, iterable, ...)
  • function: is the function that will be applied to every item of the iterable
  • iterable: is the parameter that is going to be mapped. It can be a list, tuple, etc.

Example:

#transform all the items of a string to a integer
iterable_str = ['1','2','3','4','5']
map(int,iterable_str) 
# [1, 2, 3, 4, 5]
#transform all the items of a string to a float
iterable_str = ['1.0','2.0','3.0','4.0','5.0']
map(float,iterable_str) 
# [1.0, 2.0, 3.0, 4.0, 5.0]
#transform all the items of a string by applying strings methods like capitalize
iterable_str =['finxter','is','an','endless','source','of','knowledge']
list(map(str.capitalize, iterable_str)) 
# ['Finxter', 'Is', 'An', 'Endless', 'Source', 'Of', 'Knowledge']

So now that we know the theory behind these two functions we could conclude that an acceptable solution by joining them would be this one:

my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
dict(map(reversed, my_dict.items())
# {1: 'a', 2: 'b', 3: 'c', 4: 'd'}

At this point, you could fairly think that finally, you have the right and the most pythonic solution, don’t you? Well, no… so here it comes the 4th method to provide you with more knowledge. So, keep reading! 

Method 4: Using a dictionary comprehension

Although functional programming tools like map() have been very useful in the past being fundamental components in python since more than 20 years, nowadays there are other forms that are becoming more popular among Python developers like list comprehension or dictionary comprehension.

How do they work? 

Well, a dictionary comprehension is a quick and concise way to create a dictionary into a new one by applying a transforming operation for each of its members if needed. As you may have noticed here we are focused on dictionary comprehension, however, if you are interested in list comprehension I suggest you read this great article also in Finxter.

The syntax is:

Dictionary comprehension

{ expression + context }

Example:

my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
pow3_my_dict = {k:v**3 for (k,v) in my_dict.items()} 
# {'a': 1, 'c': 27, 'b': 8, 'd': 64}

Explanation:

  • Expression: k:v**3 🡪 it tells python what to do with the values of the dictionary. In this case, we are applying the third power. This is 1^3, 2^3, 3^3, 4^3
  • Context: for (k,v) in my_dict.items() 🡪 it tells which items of the dictionary are going to be transformed. In this case, all of them. The context is an arbitrary number of for and if.

Example with an IF statement:

pow3_my_dict = {k:v**3 for (k,v) in my_dict.items() if v < 3} 
# {'a': 1, 'b': 8}

As you can see, it creates a new dictionary with the values where the IF statement is true.

Having said that, you could ask yourself: “Could I create a dictionary using the dictionary comprehension without having a previous dictionary?” Although this is a little far away from the subject we are focused, the answer is yes. We could create a new dictionary where the context is an iterable but not necessarily a dictionary. We could use the function range to generate the iterables or even using a given list. Let us see some examples:

Range function:

{num: num*num for num in range(1, 4)} 
# {1: 1, 2: 4, 3: 9}

List:

Imagine you have a list of customers that some have been introduced into the system with uppercase, lowercase or capitalized. And your job is to transform them into a dictionary in lowercase and pass the results to the system again. This could be a valid solution:

customer_list = ['Andrew@test.com', 'RITA@hooli.com', 'anne@TROAT.COM']
print({x.lower() : 1 for x in customer_list})
# {'rita@hooli.com': 1, 'anne@troat.com': 1, 'andrew@test.com': 1}

So, coming back from this parenthesis, the solution to reverse a dictionary using dictionary comprehension would be:

my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
{v: k for k,v in my_dict.items()} 
# {1: 'a', 2: 'b', 3: 'c', 4: 'd'}

Explanation:

The transformation here is to change the order the key:value pairs to have a value:key pairs. So, what we tell Python is: “Apply this transformation v,k (change the order) for every item (k,v) in the dictionary given”.

  • Expression: v:k
  • Context: for k,v in my_dict.items() 

Conclusion

In this article we have learnt how to reverse the key:value pairs of a dictionary using:

  • The structure for loop
  • The zip function
  • The map() and reversed() function, how to combine them and what is an iterable.
  • The dictionary comprehension, and the parts represented in it by the expression and the context

To explain this we have explored what a dictionary is. What their properties are such as the immutability and the uniqueness of the key. We also have covered what happens if we repeat a key with a different value or by the contrary we use a number twice as a key although one was a float type and the other was an integer type.

Finally, we have discovered that dictionary comprehension is becoming more popular than functions like map() because, if you do not abuse, it helps you to shorten the number of lines of your code making it more clean, easy to understand, elegant and more Pythonic. In case you want to get deeper in this matter please read this great article about dictionary comprehension.