Ordering a Collection
Sorting means putting the elements of a collection in a certain order.
Some types have a natural order. Numbers are ordered by value: 1 comes before 2. Strings are ordered alphabetically: "four" comes before "one". For everything else, or when you want a different order, you give a custom order with a key function: a function that turns one element into the value it should be sorted by.
Python sorts lists in two ways:
sorted(s)returns a new sorted list and leaves the original as it was. It works on any iterable.s.sort()sorts the list in place: the original order is gone.
Both take the same two keyword arguments: key= (the key function) and reverse=True for descending order. Many languages sort with a compare function that looks at two elements; Python instead asks for a key of one element and compares the keys. Almost every compare function you would write becomes a shorter key function, for example key=len to sort by length.
The examples below use the words one, two, three, four.
Natural Order
Natural order is the order a type has on its own: numbers by value, strings letter by letter.
sorted(words) gives a new list in natural order. For descending order you do not sort twice: pass reverse=True and the new list comes out turned around.
Tuples also have a natural order: Python compares them position by position and the first difference decides. That gives your own data an order for free. A version number stored as the tuple (major, minor) is compared major first, and only when the majors are equal does minor decide — exactly the reusable comparison you would otherwise write by hand.
Sorted copy
sorted() makes a new, alphabetically sorted list. The original words list is printed afterwards to show it did not change.
Output: complete Python program
words = ["one", "two", "three", "four"]
# sorted() returns a new sorted list; words stays as it was
ordered = sorted(words)
print(ordered)
print(words)
Sorted descending
reverse=True makes sorted() return the new list in descending order, so the words go from "two" down to "four".
Output: complete Python program
words = ["one", "two", "three", "four"]
# reverse=True gives the new list in descending order
desc = sorted(words, reverse=True)
print(desc)
A type with its own order
A version is the tuple (major, minor). Tuple comparison looks at major first; only when the majors are equal does minor decide. (1, 2) > (1, 3) asks "is version 1.2 greater than 1.3?" and prints False; (2, 0) > (1, 5) prints True.
Output: complete Python program
# A version is a (major, minor) tuple. Tuples compare position by
# position: major decides first, minor only breaks the tie.
v12 = (1, 2)
v13 = (1, 3)
v20 = (2, 0)
v15 = (1, 5)
# Is 1.2 greater than 1.3?
print(v12 > v13)
# Is 2.0 greater than 1.5?
print(v20 > v15)
Custom Orders
A custom order is any order you describe with a key function.
Pass it as key=: Python calls the function once per element and sorts the elements by what it returns. Python's sort is stable: elements whose keys are equal always keep their original order. You never need a separate stable sort, for example when sorting words by length.
Sorting by one property of each element is the everyday case: key=len sorts by length, and a lambda picks out anything else, such as a word's last letter.
For descending order add reverse=True. It flips the comparison of the keys, and equal elements still keep their original order.
To sort by one thing and then by another, return a tuple from the key function. Tuples compare position by position, so the second entry breaks the tie when the first one says the elements are equal.
Sort with a key function
key=len gives every word its length as the key: 3 for "aaa", 2 for "bb", 1 for "c". The smallest key comes first, so the words end up from shortest to longest. words.sort() does it in place.
Output: complete Python program
words = ["aaa", "bb", "c"]
# key=len sorts by each word's length: shorter words come first.
# sort() changes the list in place.
words.sort(key=len)
print(words)
Sort by length
The words are sorted by key=len. "one" and "two" are both 3 letters long; the stable sort keeps "one" before "two".
Output: complete Python program
words = ["one", "two", "three", "four"]
# The sort is stable: words of equal length keep their original order.
by_length = sorted(words, key=len)
print(by_length)
Sort by last letter, descending
w[-1] is the last letter of a word. With reverse=True the word with the largest last letter comes first: "four" (r), then "two" (o), then the two words ending in "e" in their original order.
Output: complete Python program
words = ["one", "two", "three", "four"]
# w[-1] is the last letter; reverse=True turns the order around.
by_last = sorted(words, key=lambda w: w[-1], reverse=True)
print(by_last)
Sort by length, then alphabetically
The key (len(w), w) is a tuple: the length first. When two words are equally long, the second entry — the word itself — orders them alphabetically.
Output: complete Python program
words = ["aaa", "bb", "c", "b", "a", "aa", "ccc"]
# The key is a tuple: length first, the word itself breaks the tie.
by_length_then_word = sorted(words, key=lambda w: (len(w), w))
print(by_length_then_word)
Check Sorted Order
Sometimes you only want to know whether a list is already sorted, without sorting it.
Python has no is_sorted() function, but the check is one line: every element must be less than or equal to its right neighbour. zip(s, s[1:]) pairs each element with the next one, and all() confirms that every pair is in order. For descending order, swap the comparison: a >= b instead of a <= b.
To check the order of one property, such as a user's age, compare that property inside the check.
Ascending and descending check
all(a <= b ...) confirms that 1, 2, 3, 4 are ascending. The swapped comparison a >= b confirms that 4, 3, 2, 1 are descending.
Output: complete Python program
ascending = [1, 2, 3, 4]
descending = [4, 3, 2, 1]
# zip(s, s[1:]) pairs each element with its right neighbour.
print(all(a <= b for a, b in zip(ascending, ascending[1:])))
# The swapped comparison checks for descending order.
print(all(a >= b for a, b in zip(descending, descending[1:])))
Check order by a field
The users are Alice (24), Bob (31) and Charlie (29). The check looks only at the ages. Bob is older than Charlie, so the list is not sorted by age and the program prints False.
Output: complete Python program
users = [("Alice", 24), ("Bob", 31), ("Charlie", 29)]
# Are the users in order of age? Compare only the ages.
ages = [age for name, age in users]
print(all(a <= b for a, b in zip(ages, ages[1:])))
Reverse Order
Reversing puts the last element first and the first element last.
The slice words[::-1] builds a reversed copy: the original keeps its order. words.reverse() reverses the list in place instead. There is also a built-in reversed(words): it returns an iterator that walks the list backwards without building a new one — wrap it in list() when you need a real list.
Reversed copy
The copy made by words[::-1] is printed, then the original is printed to show it is unchanged.
Output: complete Python program
words = ["one", "two", "three", "four"]
# words[::-1] builds a reversed copy, so the original keeps its order.
backwards = words[::-1]
print(backwards)
print(words)
Random Order
Shuffling puts the elements in a random order.
The random module has a shuffle() function. Like words.reverse(), it works in place, so shuffle a copy made with words[:] if you still need the original.
A random.Random(seed) object with a fixed seed gives the same "random" order every time the program runs with that seed. This is useful for tests and for examples like this one. The module-level random.shuffle() has no fixed seed, so the order changes on every run.
Shuffled copy
A random.Random object with seed 25 shuffles a copy of the words. With this seed the result is ['two', 'three', 'one', 'four'] on every run.
Output: complete Python program
import random
words = ["one", "two", "three", "four"]
# A fixed seed gives the same "random" order on every run.
rng = random.Random(25)
shuffled = words[:]
rng.shuffle(shuffled)
print(shuffled)