Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Sorting Data With Python
Sorting in Python is a fundamental task that you can accomplish using sorted()
and .sort()
. The sorted()
function returns a new sorted list from the elements of any iterable, without modifying the original iterable. On the other hand, the .sort()
method modifies a list in place and doesn’t return a value. Both methods support customization through optional keyword arguments like key
and reverse
.
By the end of this tutorial, you’ll understand that:
- You can sort any iterable with the
sorted()
function. - The
sorted()
function returns a new sorted list. - The
.sort()
method sorts the list in place. - You sort items in descending order by setting the
reverse
argument toTrue
. - The
key
argument accepts a function to customize the sort order.
In this tutorial, you’ll learn how to sort various types of data in different data structures, customize the order, and work with two different ways of sorting in Python. You’ll need a basic understanding of lists and tuples as well as sets. These are the data structures you’ll be using to perform some basic operations.
Get Your Cheat Sheet: Click here to download a free cheat sheet that summarizes how to use sorted() and .sort() in Python.
Take the Quiz: Test your knowledge with our interactive “How to Use sorted() and .sort() in Python” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
How to Use sorted() and .sort() in PythonIn this quiz, you'll test your understanding of sorting in Python using sorted() and .sort(). You'll revisit how to sort various types of data in different data structures, customize the order, and work with two different ways of sorting in Python.
Ordering Values With sorted()
In Python, you can sort iterables with the sorted()
built-in function. To get started, you’ll work with iterables that contain only one data type.
Sorting Numbers
You can use sorted()
to sort a list in Python. In this example, a list of integers is defined, and then sorted()
is called with the numbers
variable as the argument:
>>> numbers = [6, 9, 3, 1]
>>> sorted(numbers)
[1, 3, 6, 9]
>>> numbers
[6, 9, 3, 1]
The output from this code is a new, sorted list. When the original variable is printed, the initial values are unchanged.
This example shows four important characteristics of sorted()
:
- You don’t have to define the
sorted()
function. It’s a built-in function that’s available in any standard installation of Python. - You’re ordering the values in
numbers
from smallest to largest when you callsorted(numbers)
. When you pass no additional arguments or parameters,sorted()
orders the values innumbers
in ascending order. - You don’t change the original
numbers
variable becausesorted()
provides sorted output and doesn’t update the original value in place. - You get an ordered list as a return value when you call
sorted()
.
These points mean that sorted()
can be used on a list, and the output can immediately be assigned to a variable:
>>> numbers = [6, 9, 3, 1]
>>> numbers_sorted = sorted(numbers)
>>> numbers_sorted
[1, 3, 6, 9]
>>> numbers
[6, 9, 3, 1]
In this example, a new variable called numbers_sorted
now stores the output of the sorted()
function.
You can confirm all of these observations by calling help()
on sorted()
:
>>> help(sorted)
Help on built-in function sorted in module builtins:
sorted(iterable, /, *, key=None, reverse=False)
Return a new list containing all items from the iterable in ascending order.
A custom key function can be supplied to customize the sort order, and the
reverse flag can be set to request the result in descending order.
You’ll cover the optional arguments key
and reverse
later in the tutorial.
The first parameter of sorted()
is an iterable. That means that you can use sorted()
on tuples and sets very similarly:
>>> numbers_tuple = (6, 9, 3, 1)
>>> sorted(numbers_tuple)
[1, 3, 6, 9]
>>> numbers_set = {5, 10, 1, 0}
>>> sorted(numbers_set)
[0, 1, 5, 10]
Notice how even though the input was a set and a tuple, the output is a list because sorted()
returns a new list by definition. The returned object can be cast to a new type if it needs to match the input type. Be careful if attempting to cast the resulting list back to a set, as a set by definition is unordered:
>>> numbers_tuple = (6, 9, 3, 1)
>>> numbers_set = {5, 10, 1, 0}
>>> numbers_tuple_sorted = sorted(numbers_tuple)
>>> numbers_set_sorted = sorted(numbers_set)
>>> numbers_tuple_sorted
[1, 3, 6, 9]
>>> numbers_set_sorted
[0, 1, 5, 10]
>>> tuple(numbers_tuple_sorted)
(1, 3, 6, 9)
>>> set(numbers_set_sorted)
{0, 1, 10, 5}
When you cast the numbers_set_sorted
value to a set
, it’s unordered, as expected. If you’re curious about how sets work in Python, then you can check out the tutorial Sets in Python.
Sorting Strings
Just like lists, tuples, and sets, strings are also iterables. This means you can sort str
types as well. The example below shows how sorted()
iterates through each character in the value passed to it and orders them in the output:
>>> string_number_value = "34521"
>>> sorted(string_number_value)
['1', '2', '3', '4', '5']
>>> string_value = "I like to sort"
>>> sorted(string_value)
[' ', ' ', ' ', 'I', 'e', 'i', 'k', 'l', 'o', 'o', 'r', 's', 't', 't']
Just like before, you can use sorted()
to iterate through each element of the iterable you pass in. In a string, each element means each character, including spaces.
Note: Python sorts strings lexicographically by comparing Unicode code points of the individual characters from left to right. That’s why the uppercase I
appears before the lowercase e
.
To learn more about some of Python’s quirks when ordering strings, check out the tutorial How to Sort Unicode Strings Alphabetically in Python.
If you want to sort a sentence by words, then you can use Python’s .split()
method:
>>> string_value = "I like to sort"
>>> sorted_string = sorted(string_value.split())
>>> sorted_string
['I', 'like', 'sort', 'to']
In this example, you use .split()
to convert the original sentence into a list of words. Afterward, you sort the list instead of individual characters.
Exploring Limitations and Gotchas With Python Sorting
When sorting objects in Python, you may run into some unexpected behavior or even errors. In this section, you’ll explore some limitations and gotchas to look out for when using Python’s sorted()
function.
Handling Lists With Non-Comparable Data Types
There are data types that can’t be compared to each other using sorted()
because they’re too different. Python will return an error if you attempt to use sorted()
on a list containing non-comparable data. In the example below, you have None
and the integer zero (0
) in the same list. Python doesn’t know how to sort these two types because of their incompatibility:
>>> mixed_types = [None, 0]
>>> sorted(mixed_types)
Traceback (most recent call last):
...
TypeError: '<' not supported between instances of 'int' and 'NoneType'
This error shows why Python can’t sort the values given to it. It’s trying to put the values in order by using the less than operator (<
) to determine which value is lower in sorting order. You can replicate this error by manually comparing the two values:
>>> None < 0
Traceback (most recent call last):
...
TypeError: '<' not supported between instances of 'NoneType' and 'int'
The same TypeError
is thrown when you try to compare two non-comparable values without using sorted()
.
If the values in the list can be compared without raising a TypeError
, then the list can be sorted. This prevents sorting iterables with intrinsically unorderable values and producing output that may not make sense.
Python can implicitly convert a value to another type. Even though elements in a list look different, Python may able to interpret them as integers and compare them to each other using sorted()
:
>>> sorted([1, False, True, 0])
[False, 0, 1, True]
Python interprets the Boolean False
as 0
and True
as 1
. You can verify that Python considers the integers 0
and 1
equal to False
and True
by comparing them manually:
>>> 0 == False
True
>>> 1 == True
True
If you have a look at the ordered list from before, you can spot another important aspect of sorting called sort stability. In Python, when you sort equal values, they’ll retain their original order in the output. Since the integer 1
comes before True
in the unsorted list, 1
will appear before True
in the sorted list.
Considering Length When Sorting Similar Strings
In the example above, you were sorting either single characters or different words. When dealing with a list that contains similar strings, Python sorts shorter strings first:
>>> sorted(["aaa", "a"])
['a', 'aaa']
Strings that contain identical values will end up being sorted shortest to longest because the shorter strings lack elements to compare against the longer ones.
This doesn’t mean that shorter strings always come first:
>>> sorted(["aaa", "ab", "a"])
['a', 'aaa', 'ab']
If the first letter is the same, then sorted()
will use the second character to determine order, and so on.
In the example above, ab
is shorter than aaa
. But while traversing through the string to determine how to sort ab
compared to aaa
, the second letter of ab
is considered larger than the second letter of aaa
. That’s because the letter b
has a larger Unicode than the letter a
.
You can leverage Python’s ord()
function to investigate a character’s Unicode:
>>> ord("b")
98
>>> ord("a")
97
To learn more about some of Python’s quirks when ordering strings, check out the tutorial How to Sort Unicode Strings Alphabetically in Python.
Customizing sorted()
With Keyword Arguments
When using Python’s sorted()
function, you can optionally pass in values for the keywords reverse
and key
. This enables you to override the default behavior of sorted()
and customize the order of the output.
Sorting Iterables in Reverse Order
As the name suggests, the keyword argument reverse
let’s you reverse the order of an iterable. The reverse
keyword accepts a Boolean value:
>>> numbers = [10, 3, 7]
>>> sorted(numbers)
[3, 7, 10]
>>> sorted(numbers, reverse=True)
[10, 7, 3]
The default value of reverse
is False
, which results in the ascending order of items. If you set reverse
to True
, then the sorting will be in descending order.
Sorting Strings by Length
One of the most powerful components of sorted()
is the keyword argument called key
. This argument expects a function to be passed to it, and that function will be used on each value in the list being sorted to determine the resulting order.
To demonstrate a basic example, let’s assume the requirement for ordering a specific list is the length of the strings in the list, from shortest to longest. You can use the len()
function to return the length of a string, along with the key
argument:
>>> word = "paper"
>>> len(word)
5
>>> words = ["banana", "pie", "Washington", "book"]
>>> sorted(words, key=len)
['pie', 'book', 'banana', 'Washington']
The resulting order is a list with a string order of shortest to longest. The length of each element in the list is determined by len()
and then returned in ascending order.
Ignoring the Case When Sorting Strings
By default, sorting in Python is case sensitive. This means that words starting with an uppercase Z will be sorted before those beginning with lowercase letters because of their Unicode values:
>>> sorted(["ape", "Zebra", "elephant"])
['Zebra', 'ape', 'elephant']
You can pass in str.lower
as the value of key
to sort strings independently of a character’s case:
>>> sorted(["ape", "Zebra", "elephant"], key=str.lower)
['ape', 'elephant', 'Zebra']
During sorting, the function passed to key
is called on each element to determine sort order, but the original values remain in the output.
Avoiding Pitfalls When Using sorted()
With a key
Argument
There are two main limitations to look out for when you’re using functions with the key
argument.
First, the number of required arguments in the function passed to key
must be exactly one:
>>> def add(x, y):
... return x + y
...
>>> sorted([1, 2, 3], key=add)
Traceback (most recent call last):
...
TypeError: add() missing 1 required positional argument: 'y'
The example above shows the definition of an addition function that takes two arguments. When that function is used in key
on a list of numbers, it fails because it’s missing a second argument. Each time add()
is called during the sort, it’s only receiving one element from the list at a time.
The second limitation of key
is that the function used with key
must be able to handle all the values in the iterable.
Here, you have a list of numbers represented as strings to be used in sorted()
, and key
is going to attempt to convert them to numbers using int
:
>>> values_to_cast = ["11", "3", "2"]
>>> sorted(values_to_cast, key=int)
['2', '3', '11']
However, if a value in the iterable can’t be cast to an integer, then using int
as the value for key
will fail:
>>> values_to_cast = ["11", "3", "2", "A"]
>>> sorted(values_to_cast, key=int)
Traceback (most recent call last):
...
ValueError: invalid literal for int() with base 10: 'A'
As long as a string contains a numeric value, Python can convert the string to an integer. Since A
isn’t a numeric value, you receive a ValueError
when calling sorted()
with key=int
.
Combining sorted()
With lambda
Functions
The key
functionality is extremely powerful because it allows you to manipulate the output order using almost any function, whether built-in or user-defined.
If the ordering requirement is to order an iterable by each string spelled backwards, then you could define a function that reverses a word.
In the example below, you define a function named reverse_word()
that reverses the string passed to it. Then, you use reverse_word
as the value of key
when calling sorted()
:
>>> def reverse_word(word):
... return word[::-1]
...
>>> words = ["cookie", "banana", "donut", "pizza"]
>>> sorted(words, key=reverse_word)
['banana', 'pizza', 'cookie', 'donut']
The word[::-1]
slice syntax reverses a string. Each element will have reverse_word()
applied to it, and the sorting order will be based on the characters in the reversed version of each word. If two words have the same final letter, the next letter is compared, and so on.
As a result, the elements in words
are sorted based on their ending letters, which is why "pizza"
comes before "cookie"
but after "banana"
.
Instead of writing a standalone function, you can shorten the code and leverage the lambda
keyword. With lambda
, you can create an anonymous function, commonly refered to as a lambda
function.
By using lambda
, you can define a function inline and use it directly as the value of key
. Instead of defining and calling reverse_word()
, you can accomplish the same result with fewer lines of code:
>>> words = ["cookie", "banana", "donut", "pizza"]
>>> sorted(words, key=lambda word: word[::-1])
['banana', 'pizza', 'cookie', 'donut']
In the example above, the key
is defined as a lambda
. The lambda
function takes one argument named word
. Then, word[::-1]
is called on each element and reverses the word. That reversed output is then used for sorting, but the original words are still returned.
Ordering Values With .sort()
So far, you’ve learned about Python’s sorted()
function. However, you may have come across a method with a similar name—the .sort()
method:
>>> help(list.sort)
Help on method_descriptor:
sort(self, /, *, key=None, reverse=False) unbound builtins.list method
Sort the list in ascending order and return None.
The sort is in-place (i.e. the list itself is modified) and stable (i.e. the
order of two equal elements is maintained).
If a key function is given, apply it once to each list item and sort them,
ascending or descending, according to their function values.
The reverse flag can be set to sort in descending order.
At first glance, the description of .sort()
looks similar to the output of help(sorted)
, which you explored earlier. Before taking a look at the similarities between .sort()
and sorted()
, it’s important to first understand their differences.
Understanding the Differences Between .sort()
and sorted()
The .sort()
method accomplishes more or less the same thing as the sorted()
function. But there are four critical differences between .sort()
and sorted()
:
.sort()
is a method of thelist
class..sort()
can only be used with lists..sort()
returnsNone
..sort()
modifies the order of elements in place.
As a method, .sort()
works with the list instance itself. In other words, you don’t explicitly pass in an iterable as an argument.
Have a look at the impacts of these differences in code:
>>> tuple_val = (5, 1, 3, 5)
>>> tuple_val.sort()
Traceback (most recent call last):
...
AttributeError: 'tuple' object has no attribute 'sort'
>>> values_to_sort = list(tuple_val)
>>> returned_from_sort = values_to_sort.sort()
>>> print(returned_from_sort)
None
>>> print(values_to_sort)
[1, 3, 5, 5]
When you try calling .sort()
with a tuple, you get an AttributeError
because .sort()
only exists for lists.
Then, there are some other pretty dramatic differences in how .sort()
operates compared to sorted()
in this code example:
.sort()
returnsNone
, so the assignment toreturned_from_sort
isNone
and not an ordered list.- Calling
.sort()
changes thevalues_to_sort
list in place, and the original order is not maintained in any way.
These differences in behavior make .sort()
and sorted()
absolutely not interchangeable in code, and they can produce wildly unexpected outcomes if one is used in the wrong way.
Using Keywords Arguments With .sort()
and sorted()
The .sort()
method has the same key
and reverse
optional keyword arguments that produce the same robust functionality as sorted()
.
Revisit some examples from before, this time using .sort()
instead of sorted()
:
>>> numbers = [10, 3, 7]
[3, 7, 10]
>>> numbers.sort(reverse=True)
>>> numbers
[10, 7, 3]
Just like when you used sorted()
, if you set reverse
to True
when calling .sort()
on a list, then the sorting will be in descending order.
When you pass in str.lower
as the value of key
, you can sort strings independently of a character’s case:
>>> animals = ["ape", "Zebra", "elephant"]
>>> animals.sort(key=str.lower)
>>> animals
['ape', 'elephant', 'Zebra']
During sorting, the function passed to key
is being called on each element to determine the sort order.
If you want to practice using .sort()
, then try refactoring the sorted()
examples from earlier sections with .sort()
. When doing so, keep in mind that .sort()
only works with lists.
Deciding When to Use sorted()
vs .sort()
If you’re sorting an iterable that isn’t a list, then you must use sorted()
. But if you’re working with a list, then you can use either sorted()
or .sort()
.
Generally, if you keep the similarities and differences in mind, then you can use either sorted()
or .sort()
. However, there can be situations where it’s important to choose the right tool for the task at hand.
Let’s say there’s a 5K race coming up and you need to capture and sort the race data. The data that needs to be captured is the runner’s bib number and the number of seconds it took to finish the race.
To keep things tidy, you decide to use a named tuple for convenient access:
>>> from collections import namedtuple
>>> Runner = namedtuple("Runner", "bib_number duration")
As the runners cross the finish line, each Runner
will be added to a list called runners
. In 5K races, not all runners start at the same time, so the first person to cross the finish line might not actually be the fastest person:
>>> runners = []
>>> runners.append(Runner("2528567", 1500))
>>> runners.append(Runner("7575234", 1420))
>>> runners.append(Runner("2666228", 1600))
>>> runners.append(Runner("2425201", 1490))
>>> runners.append(Runner("1235277", 1620))
>>> # Thousands and Thousands of entries later...
>>> runners.append(Runner("2526674", 1906))
Each time a runner crosses the finish line, you add their bib number and total duration in seconds to the runners
list.
The top five fastest participants are the winners that get prizes, and the remaining runners will be sorted by fastest time. There are no requirements for multiple types of sorting by various attributes. The list is a reasonable size, and there’s no mention of storing the list somewhere.
In other words, you need to sort runners
by duration
and grab the five participants with the lowest duration:
>>> runners.sort(key=lambda runner: runner.duration)
>>> top_five_runners = runners[:5]
You use a lambda
in the key
argument to get the duration
attribute from each runner and sort runners
in place using .sort()
. After runners
is sorted, you store the first five elements in top_five_runners
.
Mission accomplished—or so you think!
The race director now informs you that every forty-second runner to cross the finish line will receive a free gym bag.
That’s a problem! By using .sort()
, you changed runners
irreversibly. There’s no way to recover the original list of runners in the order they finished and find every forty-second person.
In hindsight, you should’ve sorted the runners with sorted()
and used the same lambda
:
>>> runners_by_duration = sorted(runners, key=lambda runner: runner.duration)
>>> top_five_runners = runners_by_duration[:5]
By using sorted()
, you can keep the original list of runners intact without overwriting it. This means that you can now find every forty-second person that crosses the finish line:
>>> gym_bag_winners = runners[::42]
You create the gym_bag_winners
list by leveraging the slice syntax on runners
, which still contains the original order of runners who cross the finish line.
If you’re working with important data and there’s even a remote possibility that you might need to recover the original order, then using .sort()
is not the best option. However, if the data is a copy, unimportant information, or data that can be easily re-created, then .sort()
can be a fine option.
Conclusion
The .sort()
method and sorted()
function can provide exactly the sort order you need if you use them properly with both the reverse
and key
optional keyword arguments.
Both have different characteristics when it comes to output and in-place modifications, so make sure you think through any application functionality or program requirements before choosing your approach.
Get Your Cheat Sheet: Click here to download a free cheat sheet that summarizes how to use sorted() and .sort() in Python.
Frequently Asked Questions
Now that you have some experience with sorting in Python, you can use the questions and answers below to check your understanding and recap what you’ve learned.
These FAQs are related to the most important concepts you’ve covered in this tutorial. Click the Show/Hide toggle beside each question to reveal the answer.
You can sort a list in Python using either sorted()
or .sort()
. For example, calling sorted(words)
or words.sort()
.
The .sort()
method works only with lists, while the sorted()
function can be used with any iterable.
The .sort()
method sorts a list in place and returns None
, whereas sorted()
creates a new sorted list and doesn’t alter the original data.
You can sort numbers in descending order by passing the reverse=True
argument to either sorted()
or .sort()
. This argument will reverse the order, showing the larger numbers first.
The key
argument allows you to specify a function to be called on each list element prior to making comparisons, enabling customized sorting based on specific criteria.
You can’t sort a list with non-comparable data types directly, as Python will raise a TypeError
. All elements must be comparable, or you need a custom key
function to handle the comparison.
Take the Quiz: Test your knowledge with our interactive “How to Use sorted() and .sort() in Python” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
How to Use sorted() and .sort() in PythonIn this quiz, you'll test your understanding of sorting in Python using sorted() and .sort(). You'll revisit how to sort various types of data in different data structures, customize the order, and work with two different ways of sorting in Python.
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Sorting Data With Python