# How to Sort a Dict in Descending Order by Value With Python

In this post, you will learn how to sort a Python dictionary by value descending i.e. in reverse order.

Say that you have the following dictionary containing your grades associated with a subject. You want to sort the values, in this case the grades, in a descending manner - the highest grade will appear first and the lowest last.

For example, you have this:
```python
grades = {"Math": 34, "Science": 12, "English": 89, "Physics": 8}
```

... And you want this:
```python
{'English': 89, 'Math': 34:, 'Science': 12:, 'Physics': 8}
```

You can do this is at least 3 different ways.

## Sorting a dict by value descending using list comprehension

The quickest way is to iterate over the key-value pairs of your current `dict` and call `sorted` passing the dictionary values and setting `reversed=True`.

 If you are using Python 3.7, regular `dict`s are ordered by default. So let's use it!

```python
>>> grades = {"Math": 34, "Science": 12, "English": 89, "Physics": 8}
>>> grades
{'Math': 34, 'Science': 12, 'English': 89, 'Physics': 8}
>>> value_key_pairs = ((value, key) for (key,value) in grades.items())
>>> sorted_value_key_pairs = sorted(value_key_pairs, reverse=True)
>>> sorted_value_key_pairs
[(89, 'English'), (34, 'Math'), (12, 'Science'), (8, 'Physics')]
>>> {k: v for v, k in sorted_value_key_pairs}
 {'English': 89, 'Math': 34, 'Science': 12, 'Physics': 8}
```

*And Voila!* You have your sorted grades `dict` in a descending fashion.

> What if I have Python 3.6 or lower?

In this case, you can use `OrderedDict` from the `collections` module.

```python
>>> from collections import OrderedDict

>>> OrderedDict((k, v) for v, k in sorted_value_key_pairs)
OrderedDict([('English', 89), ('Math', 34), ('Science', 12), ('Physics', 8)])
```

## Sorting a dictionary in descending order using the `operator` module

The `operator` module provides a functional interface to built-in operators like `<`, `>`, `==` and so on.

This module has many useful functions and one of them is the `itemgetter`. This function returns a callable object that will fetch the item using the `__getitem__()` method. 

In a nutshell, if you do `callable = operator.itemgetter(1)`, and pass a *subscriptable* object, say `('Physics', 8)` to this *callable*, it will return the equivalent of `('Physics', 8)[1]`.

For example,

```python
>>> subject_grade_pair = ('Physics', 8)

>>> get_grade = operator.itemgetter(1)

>>> get_grade(subject_grade_pair)
8

>>> subject_grade_pair[1]
8
```

Now, the question is, how can we use this to sort the values?

The `sorted` built-in function expects not only the *iterable* you want to sort but also a *key*. This key argument is nothing more than a function of one argument that you can feed each item of the list. And that’s exactly what we need to sort our list!

```python
>>> import operator

# remember, the grade is the second item in the subject - grade pair
>>> sort_by_grade = operator.itemgetter(1)

>>> grades = {"Math": 34, "Science": 12, "English": 89, "Physics": 8}
>>> grades
{'Math': 34, 'Science': 12, 'English': 89, 'Physics': 8}

>>> sorted_value_key_pairs = sorted(grades.items(), key=sort_by_grade, reverse=True)
>>> {k: v for v, k in sorted_value_key_pairs}
 {'English': 89, 'Math': 34, 'Science': 12, 'Physics': 8}
```

At this point you might wonder: 

> This `sort_by_grade` looks like a glorified lambda...

Well, good shout, this brings us to the last section.

## Using `lambda` to sort the dictionary in descending order

So, as we saw in the previous section, `operator.itemgetter` returns a callable that is equivalent to calling the `__getitem__()` method on a *subscriptable* object.

This is remarkably similar to pass a lambda as a key which takes a tuple, say `(“Math”, 34)`, and returns the second item which is the grade.

```python
>>> sort_by_grade_lambda = lambda subject_grade_pair: subject_grade_pair[1]

>>> sorted_value_key_pairs = sorted(grades.items(), key=sort_by_grade_lambda, reverse=True)

>>> {k: v for v, k in sorted_value_key_pairs}
 {'English': 89, 'Math': 34, 'Science': 12, 'Physics': 8}
```

And this is how you use a `lambda` function to sort a dict items by value in descending order.

## Sorting a dictionary with complex objects as values

So far we've only dealt with simple objects such as `int`. What happens if we have a complex object, such as a custom `Grade` object as a dictionary value?

Let's see how it works.

```python
class Grade:
    def __init__(self, grade: int, cutoff: int = 70):
        self.grade = grade
        self.cutoff = cutoff
        self.passed = grade >= cutoff
        
    def __repr__(self):
        return f"<Grade(grade={self.grade}, cutoff={self.cutoff}, passed={self.passed}>"
```

Let's try to sort it...

```python
>>> grades = {"Math": Grade(grade=34), "Science": Grade(grade=12), "English": Grade(grade=89), "Physics": Grade(grade=8)}
>>> grades
grades = {"Math": Grade(grade=34), "Science": Grade(grade=12), "English": Grade(grade=89), "Physics": Grade(grade=8)}

>>> value_key_pairs = ((value, key) for (key,value) in grades.items())
>>> sorted_value_key_pairs = sorted(value_key_pairs, reverse=True)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-0c94e26fda4a> in <module>
----> 1 sorted_value_key_pairs = sorted(value_key_pairs, reverse=True)

TypeError: '<' not supported between instances of 'Grade' and 'Grade'
```

Oops! It didn't work. The reason is that, as the error message says, `Grade` doesn't implement the `__lt__` operator, which makes it impossible to compare them.

To fix that we can either implement the `__lt__` method or use the lambda as we used before with an adaptation. Let's see the lambda approach first.

```python
>>> sort_by_grade_lambda = lambda subject_grade_pair: subject_grade_pair[1].grade

>>> sorted_value_key_pairs = sorted(grades.items(), key=sort_by_grade_lambda, reverse=True)

>>> {k: v for v, k in sorted_value_key_pairs}
{<Grade(grade=89, cutoff=70, passed=True>: 'English',
 <Grade(grade=34, cutoff=70, passed=False>: 'Math',
 <Grade(grade=12, cutoff=70, passed=False>: 'Science',
 <Grade(grade=8, cutoff=70, passed=False>: 'Physics'}
```

### Implementing `__lt__`

Let's see how it looks when we implement the `<` operator.

```python
class Grade:
    def __init__(self, grade: int, cutoff: int = 70):
        self.grade = grade
        self.cutoff = cutoff
        self.passed = grade >= cutoff
      
    def __lt__(self, other: "Grade") -> bool:
        return self.grade < other.grade
        
    def __repr__(self):
        return f"<Grade(grade={self.grade}, cutoff={self.cutoff}, passed={self.passed}>"

>>> grades = {"Math": Grade(grade=34), "Science": Grade(grade=12), "English": Grade(grade=89), "Physics": Grade(grade=8)}

>>> grades
{'Math': <Grade(grade=34, cutoff=70, passed=False>,
 'Science': <Grade(grade=12, cutoff=70, passed=False>,
 'English': <Grade(grade=89, cutoff=70, passed=True>,
 'Physics': <Grade(grade=8, cutoff=70, passed=False>}

>>> value_key_pairs = ((value, key) for (key,value) in grades.items())

>>> sorted_value_key_pairs = sorted(value_key_pairs, reverse=True)

>>> sorted_value_key_pairs
[(<Grade(grade=89, cutoff=70, passed=True>, 'English'),
 (<Grade(grade=34, cutoff=70, passed=False>, 'Math'),
 (<Grade(grade=12, cutoff=70, passed=False>, 'Science'),
 (<Grade(grade=8, cutoff=70, passed=False>, 'Physics')]

>>> {k: v for v, k in sorted_value_key_pairs}
{'English': <Grade(grade=89, cutoff=70, passed=True>,
 'Math': <Grade(grade=34, cutoff=70, passed=False>,
 'Science': <Grade(grade=12, cutoff=70, passed=False>,
 'Physics': <Grade(grade=8, cutoff=70, passed=False>}
```

*And Voila!* You have your grades dictionary sorted by value in a descending way.

## Conclusion

In this post we saw 3 different ways of sorting a dictionary in descending order with Python. I hope you find it useful.

Other posts you may like:

- [Design Patterns That Make Sense in Python: Simple Factory](#https://miguendes.me/design-patterns-that-make-sense-in-python-simple-factory)
- [How to Pass Multiple Arguments to a map Function in Python](https://miguendes.me/how-to-pass-multiple-arguments-to-a-map-function-in-python)
- [73 Examples to Help You Master Python's f-strings](https://miguendes.me/73-examples-to-help-you-master-pythons-f-strings)
- [3 Ways to Test API Client Applications in Python](https://miguendes.me/3-ways-to-test-api-client-applications-in-python)
- [Everything You Need to Know About Python's Namedtuples](https://miguendes.me/everything-you-need-to-know-about-pythons-namedtuples)
- [The Best Way to Compare Two Dictionaries in Python](https://miguendes.me/the-best-way-to-compare-two-dictionaries-in-python)
- [5 Hidden Python Features You Probably Never Heard Of](https://miguendes.me/5-hidden-python-features-you-probably-never-heard-of)


See you next time!



