## Introduction

Sorting is an extremely common task performed on lists in Python in many applications. A website needs to sort a list of users accordingly to their name; an online shopping application might want to sort products based on their prices; a university portal might want to sort students according to their GPA; and so on.

In addition to this, some common algorithms out there that operate on lists require them to be sorted. The highly efficient binary search is a perfect example.

In Python, there are two ways to sort a list: one is using the `sort()`

method of lists, and the other is using the global `sorted()`

function. In this chapterm we shall discover both these ways in meticulous detail.

## Simple sorting

The most straightforward way to sort a list is to call ** sort()** on it, without any arguments.

It will sort all the items of the list in increasing order, also known as ascending order, or alphabetical order.

The `sort()`

method, as we already know, sorts a list by side effect. That is, it doesn't return a new sorted list; rather it sorts the list in place and returns `None`

itself.

`sort()`

method mutates the list it's called on.Following we have a list of numbers that we want to print in increasing order:

`nums = [4, 0, 1, 18, 6, -3, -50]`

To do so, we would go on and call the `sort()`

method on this list and then print it:

```
nums = [4, 0, 1, 18, 6, -3, -50]
nums.sort()
print(nums)
```

Calling `nums.sort()`

sorts `nums`

in place, after which we refer back to it in order to print it.

## Sorting in decreasing order

To sort a list in decreasing order, set the `reverse`

keyword argument to `sort()`

to `True`

.

`list.sort(`*reverse=True*)

As the name suggests, the `reverse`

keyword argument specifies whether to sort the list in reverse order i.e decreasing order. By default, it's `False`

and so the list doesn't get sorted in reverse order.

Below we sort the same list `nums`

above, this time in decreasing order:

```
nums = [4, 0, 1, 18, 6, -3, -50]
nums.sort(reverse=True)
print(nums)
```

## Sorting with a key

Apart from `reverse`

, the `sort()`

method can be provided one more keyword argument and that is ** key**.

`list.sort(`*key=None*, *reverse=False*)

`key`

specifies a function to be called on each element of the list being sorted to return a value to be used for comparison in the underlying sorting algorithm.

Let's see how it works.

Suppose we have a list of students, each represented using a tuple whose first item is the stundent's name and the second item is the student's age:

`students = [("Mark", 20), ("James", 19), ("Sandra", 20), ("Bill", 21)]`

Now let's say we want to sort this list based on the name of each student. Calling `sort()`

, as is, won't work in this case since each item is a tuple, and therefore can't be validly compared with another one.

What we need to do is to tell Python what to use in comparing two items. This is where `key`

comes in.

```
students = [("Mark", 22), ("James", 19), ("Sandra", 20), ("Bill", 21)]
def get_age(student):
return student[1]
students.sort(key=get_age)
print(students)
```

We create a function `get_age()`

and pass that as `key`

to `sort()`

. Now whenever an item in the list is compared against another (in the underlying sorting algorithm), this function is called on both of them and the names of the students retrieved, respectively.

Whichever student's age is smaller than the other one's, it gets ordered first.

We can use `key`

to sort lists in complex ways.

An example, sorting a list of co-ordinates based on their distances from the origin, is demonstrated below:

```
points = [(0, 5), (3, 5), (6, 6), (0, 0), (2, 9), (4, 12)]
def distance(point):
# pythagoras's theorem
return (point[0] ** 2 + point[1] ** 2) ** 2
points.sort(key=distance)
print(points)
```

Given a point (represented as a tuple of two items: the x co-ordinate followed by the y co-ordinate), the function `distance()`

returns its distance from the origin, computed using the very famous Pythagoreon Theorem.

This function is set as the `key`

of `points.sort()`

. It's called by `sort()`

for each of the elements of `points`

, and then the comparison is made over the returned value, that is the distance of the respective point from the origin.

The point with the least amount of distance is put first, while the point with the largest distance is put last. In short, `points`

is sorted according to the distance of each point, in increasing order.

Here's the output:

## Sorting using `sorted()`

Uptil this point in this chapter, we've been considering sorting examples using the `sort()`

method of lists. The `sort()`

method mutates a given list, and doesn't itself return anything.

This means that if we want to work with a sorted version of a list without modifying its original order, we have to do some additional work of copying the list.

In the code below, we ought to work with a sorted configuration of `nums`

, but at the same time, need its original order preserved. This is possible by first making a copy of `nums`

, and then sorting this copy:

```
nums = [8, 5, 1, 3, 0, 4, 4, 12, 19]
nums2 = nums[:]
nums2.sort()
# work with nums2
print(nums2)
```

The thing is that, often times, this boilerplate can become frustrating — we want to quickly work with a list's sorted version, and then forget it later on; why create another list?

This is where ** sorted()** comes in.

`sorted(`*key=None*, *reverse=False*)

The `sorted()`

function works exactly how `sort()`

does — there is no single difference in the syntax of both these methods, except for that the former doesn't mutate the original list — rather it returns a new list in a sorted configuration.

`sorted()`

method is meant to right away return the sorted list, be it any order, using any key.Here's a comparison of `sort()`

and `sorted()`

:

Utility | `sort()` method | `sorted()` function |
---|---|---|

List mutation | Yes | No |

Return value | `None` | The list |

Parameters | `key` and `reverse` | The list to sort, `key` and `reverse` |

Let's consider a quick example:

We want to print out each element in a list `nums`

in increasing order, without modifying its original order. Obviously, this is much convenient using `sorted()`

:

```
nums = [8, 5, 1, 3, -19]
for num in sorted(nums):
print(num)
print(nums)
```

1

3

5

8

[8, 5, 1, 3, -19]

The first five prints here are the elements of `nums`

in increasing order. Then the list `nums`

is printed to see whether it has been changed or not. As expected, it is untouched.