If you are out there exploring the world of Python, you will most likely have heard a lot of hype about list comprehension, but did you know there is also such a thing as dictionary comprehension? For anyone who is reading this and is not familiar with list comprehension, see my previous blog for help with that. This blog will be expanding on that knowledge to discuss the basics of dictionary comprehension, how it compares to list comprehension, and what we can do with it.
Like list comprehension, dictionary comprehension takes in a group of values, performs some kind of task on them, and returns the result, but the major difference from list comprehension is that the result is in the form of a dictionary rather than a list. Before going further into this, make sure you understand what a dictionary is and how it works.
The general syntax for dictionary comprehension looks like this:
{resulting_keys: resulting_values for iteration in series}
Since a dictionary is stored as a series of key-value pairs separated by a colon, it makes sense that the output portion of the dictionary comprehension, resulting_keys: resulting_values, looks exactly like a key-value pair within a dictionary. Intuitively, we wrap dictionary comprehensions in the same curly brackets that we would use to designate a dictionary as well.
The input for a dictionary comprehension does not have to be a dictionary, but the simplest way to explain how it works would be to start off with an example of converting one dictionary to another.
Say I have the following dictionary:
my_dict = {‘a’: 1, ‘b’: 2, ‘c’: 3, ‘d’: 4, ‘e’: 5}
And I want to modify this so that the values are all multiplied by 2. We can do this with a simple dictionary comprehension, like so:
new_dict = {key: value * 2 for key, value in my_dict.items()}
The new_dict will now look like this:
{‘a’: 2, ‘b’: 4, ‘c’: 6, ‘d’: 8, ‘e’: 10}
The major difference in this syntax from a list comprehension is that instead of iterating over one group of values, the dictionary comprehension is iterating over two groups in tandem, a group of keys and a group of values. This is why there are two iterating variables in this case, key, value, which translate to a final key: value pair. The items() method converts the dictionary into a list of tuples that can be read as (key1, value1), (key2, value2), (key3, value3), etc.
In the above example, we only modified the values and passed the keys to the new dictionary as is, but we could modify both the keys and the values at the same time if we wanted to. For example, if I wanted to capitalize all the letters in my_dict as well as multiply all the numbers by 2, we could do that like this:
new_dict = {key.upper(): value * 2 for key, value in my_dict.items()}
Then new_dict would look like this:
{‘A’: 2, ‘B’: 4, ‘C’: 6, ‘D’: 8, ‘E’: 10}
In a way, we can think of this as performing two list comprehensions at once, one for the keys and one for the values. We don?t have to have two iterating variables in every case though. For example, take a look at the list of words below:
words = [‘car’, ‘house’, ‘plant’, ‘fisherman’, ‘picnic’, ‘rodeo’]
What if I wanted to create a dictionary from this list, where the keys would be the words themselves, and the values would be the number of letters in each word. Here?s how I would do that:
word_dict = {word: len(word) for word in words}
Now we have a word_dict that looks like this:
{‘car’: 3, ‘house’: 5, ‘plant’: 5, ‘fisherman’: 9, ‘picnic’: 6, ‘rodeo’: 5}
Since the keys and the values of this dictionary are both a function of the same words list, we only need one iterating variable to generate this dictionary, and it?s relatively simple to accomplish.
Conditionals Within Dictionary Comprehensions
We can also do filtering and/or conditional logic inside a dictionary comprehension. This works basically in the same way as it would in a list comprehension. Here?s an example of filtering a dictionary:
my_dict = {‘a’: 1, ‘b’: 2, ‘c’: 3, ‘d’: 4, ‘e’: 5}new_dict = {key: val for key, val in my_dict.items() if val > 2}
This will return only the key-value pairs in which the value is greater than 2, so new_dict will be:
{‘c’: 3, ‘d’: 4, ‘e’: 5}
We can filter based on the keys as well. Let?s add one more filter to the above example based on the keys this time:
new_dict = {key: val for key, val in my_dict.items() if val > 2 if key != ‘d’}
First, we filtered out any key-value pairs that were not greater than two, and then we also filtered out any key-value pairs that had a key of ‘d’. The result of new_dict is now:
{‘c’: 3, ‘e’: 5}
We can use if and else statements together in dictionary comprehension as well, but just like in list comprehension, the syntax gets switched around once else is involved:
my_dict = {‘a’: 1, ‘b’: 2, ‘c’: 3, ‘d’: 4, ‘e’: 5}new_dict = {key: val + 10 if val > 3 else val + 20 for key, val in my_dict.items()}
Output:
{‘a’: 21, ‘b’: 22, ‘c’: 23, ‘d’: 14, ‘e’: 15}
An important thing to note here is that the conditions cannot apply to both the keys and the values together. You have to treat them as separate. In other words, this code will throw a syntax error:
new_dict = {key: val + 10 if val > 3 else key: val + 20 for key, val in my_dict.items()}
The problem here is in the key: val + 20 because the else statement does not recognize the key, only the val. You can apply conditionals to the keys as well as the values, but it would have to look something like this:
new_dict = {(key.upper() if val > 2 else key): (val + 10 if val > 3 else val + 20) for key, val in my_dict.items()}
I wrapped the two sets of conditionals in parentheses in order to make this easier to visualize, although this is not required for the code to work. The first set of parentheses will capitalize the last three keys in my_dict and the second set of parentheses will add 20 to the first three values and add 10 to the last two values, so the new_dict will now be:
{‘a’: 21, ‘b’: 22, ‘C’: 23, ‘D’: 14, ‘E’: 15}
You can also string multiple if and else statements together, however, this can get a bit verbose and at a certain point become difficult to read. Just something to keep in mind.
Nested Dictionary Comprehensions
Like list comprehensions, dictionary comprehensions can also be nested within each other. If we have a dictionary of dictionaries, we can modify them with nested dictionary comprehensions. Here?s an example where we multiply every number in the nested dictionaries below by 10:
my_dict = { ‘A’: { ‘a’: 1, ‘b’: 2, ‘c’: 3}, ‘B’: { ‘d’: 4, ‘e’: 5, ‘f’: 6}}new_dict = {outer_key: {inner_key: inner_val * 10 for inner_key, inner_val in outer_val.items()} for outer_key, outer_val in my_dict.items()}
Output:
{‘A’: {‘a’: 10, ‘b’: 20, ‘c’: 30}, ‘B’: {‘d’: 40, ‘e’: 50, ‘f’: 60}}
This above example may be tough to wrap your head around at first. I would start by thinking about what the inner dictionary comprehension is doing first. Remember that the result of that as a whole represents the new set of values for the outer dictionary. So it can be thought of as such:
new_dict = {outer_key: {outer_val} for outer_key, outer_val in my_dict.items()}
The outer_val is actually its own dictionary, which we are doing a dictionary comprehension on for each inner dictionary. That is nested dictionary comprehensions in a nutshell.
As with list comprehension, this represents only the beginning of what can be done with dictionary comprehension, but from here hopefully, you can find your way through the rest.
Happy coding!