Skip to content →

Sorting a Dictionary by Value in Python

I have a dictionary that looks like this,

data = {
  'red': 1,
  'black': 3,
  'green': 2
}

and I want to sort it by value, so it looks like this:

{ 'red': 1, 'green': 2, 'black': 3 }

Data in dictionaries is retrieved in three different ways.

  1. In key, value pairs (.items())
  2. Just the keys (.keys())
  3. Just the values (.values())

Python has a builtin sorted() function that will be useful. I usually only pass one thing to sorted, for example a list, but it turns out there are other parameters to this function: key and reverse.

Let’s look at that key parameter. We can set key to a function such as len(), that would allow us to sort a list based on the len() of its elements, for example.

So, we wanted to sort our dictionary by values, right?

First, let’s see what happens when we just use sorted without the key parameter.

data = {
  'red': 1,
  'black': 3,
  'green': 2
}

print(sorted(data))
['black', 'green', 'red']

It appears to sort by the keys, alphabetically. I wonder what happens if I add a key that is not a string.

data = {
  'red': 1,
  'black': 3,
  'green': 2,
  55555: 'foo'
}

print(sorted(data))
TypeError: '<' not supported between instances of 'int' and 'str'

Oops.

Well, that gives us a glimpse into what is happening under the hood. Python is comparing the keys, and it cannot compare an int to a str.

Anyways, let’s get back to trying to sort our dictionary by values.

data = {
  'red': 1,
  'black': 3,
  'green': 2
}

print(sorted(data, key=data.values()))
TypeError: 'dict_values' object is not callable

Hmm. I must be using the function wrong, let me check the docs.

sorted(iterable*key=Nonereverse=False)

key specifies a function of one argument that is used to extract a comparison key from each element in iterable (for example, key=str.lower). The default value is None (compare the elements directly).

python3 doc

Maybe that was the wrong approach. data.values() will return an array of the values. That is not a function 😛

I could use lambda to kind of coerce it into a function. Let’s try that.

data = {
  'red': 1,
  'black': 3,
  'green': 2
}

print(sorted(data, key=lambda x: x[1]))
['red', 'black', 'green']

Not quite there. Recall that sorted without parameters only looked at the keys. In the lambda, x would be the key. So we are actually sorted by the second letter in each key (key[1]).. haha! Let’s verify that.

data = {
  'red': 1,
  'black': 3,
  'gaeen': 2 # see what I did here?
}

print(sorted(data, key=lambda x: x[1]))
['gaeen', 'red', 'black']

My intention with x[1] in my lambda function was to get the value of the key. But I forgot that I needed to retrieve the data using .items(), which returns both the key and the value. So with a slight change, I should get the data sorted by value.

data = {
  'red': 1,
  'black': 3,
  'gaeen': 2
}

print(sorted(data.items(), key=lambda x: x[1])) # note: change data -> data.items()
[('red', 1), ('gaeen', 2), ('black', 3)]

Gottem!

Published in Today I Learned