Let’s say you have a list of tuples in Python:

tuple_list = [(1, 1, 5), (0, 1, 3), (0, 2, 4), (1, 3, 4)]

You can sort this list with the built-in sorted() function:

sorted(tuple_list)

# Expected result
# [(0, 1, 3), (0, 2, 4), (1, 1, 5), (1, 3, 4)]

The output of this call is the same list with tuples sorted by the first element with ties broken by subsequent elements in the tuples. This works as-is because Python has a way to compare two tuples: it simply evaluates each element one at a time until it finds a difference. This means that the expression (0, 1, 3) > (0, 1, 2) evaluates to true.

You can also sort the list in-place:

# This returns None, but tuple_list will now be sorted
tuple_list.sort()

sorted() and sort() both accept key and reverse keyword arguments that can be used to modify the default behavior.

key

The key argument lets you specify a custom sort order. It accepts a function that takes an element and returns the value you want to compare. So if you want to sort by the second element you can do the following:

from operator import itemgetter

sorted(tuple_list, key=itemgetter(1))

# Expected result
# [(0, 1, 3), (1, 1, 5), (0, 2, 4), (1, 3, 4)]

You will often see people use something like lambda x: x[1] instead of itemgetter(). This approach is good to be aware of because you can use it if the items in your list are arbitrary objects. But itemgetter() is a little faster when you just need to access indices. Another cool thing about itemgetter() is that you can pass in multiple arguments:

sorted(tuple_list, key=itemgetter(2, 1))

# Expected result
# [(0, 1, 3), (0, 2, 4), (1, 3, 4), (1, 1, 5)]

This will sort the list by the third element, using the second element to break ties. You can prove it to yourself by calling the function on a tuple directly:

itemgetter(2, 1)((0, 2, 4))

# Expected result
# (4, 2)

reverse

You can also sort your list in descending order by passing in reverse=True:

sorted(tuple_list, reverse=True)

# Expected result
# [(1, 3, 4), (1, 1, 5), (0, 2, 4), (0, 1, 3)]

Finally, say you want to sort by:

  1. The second element, ascending
  2. The third element, descending

You can accomplish this by sorting twice in reverse priority order:

sorted(sorted(tuple_list, key=itemgetter(2), reverse=True), key=itemgetter(1))

# Expected result
# [(1, 1, 5), (0, 1, 3), (0, 2, 4), (1, 3, 4)]

This works because TimSort (which Python uses under the hood) is stable, meaning the order of the non-sorting indices won’t be changed if you don’t explicitly sort on them.