Lists are one of the fundamental data structures in Python. Often we need to sort the elements of a list in a particular order - either ascending or descending. Python provides many flexible and efficient ways to sort lists. This article will provide an in-depth look at the various methods for sorting lists in Python.
Table of Contents
Open Table of Contents
Overview of Sorting Lists in Python
There are two main ways to sort lists in Python:
-
Using the
sorted()
function to return a new sorted list copy leaving the original list unchanged. -
Using the
list.sort()
method to sort a list in-place, mutating the original list.
Additionally, we can customize how lists are sorted by providing a key
function that transforms each element before comparing them. This allows advanced sorting logic rather than just sorting by the natural order.
Below we will explore practical examples of each method along with sample code snippets. But first, let’s understand how sorting works in Python.
How Sorting Works in Python
Before using the sorting methods, it helps to know a bit about their implementation under the hood.
Python’s sorting algorithms rely on the __lt__()
(less than) method to compare elements. This method returns True if one element should be sorted before another.
For example:
5 __lt__(10) # Returns True
This implies that 5 should be sorted before 10. Python sorts the list by recursively making these comparisons for each pair of elements.
For custom classes, we can override the __lt__()
method to define custom sorting logic.
Now let’s see how to leverage these techniques for sorting lists in practice.
The sorted() Function
The simplest way to get a sorted version of a list is to use the built-in sorted()
function.
Syntax
sorted(iterable, key=None, reverse=False)
iterable
- Any iterable object like a list, tuple, string, etc.key
(optional) - A function to customize sorting order.reverse
(optional) - A boolean to sort in descending order ifTrue
. Default is ascending order.
Example Usage
# List of numbers
numbers = [5, 1, 4, 2, 3]
sorted_numbers = sorted(numbers)
print(sorted_numbers)
# Output: [1, 2, 3, 4, 5]
The sorted()
function returns a new list containing the elements of the original iterable in sorted order.
Let’s look at a few more examples.
# String
sorted_string = sorted("Python")
print(sorted_string)
# Output: ['P', 'h', 'n', 'o', 't', 'y']
# Tuple
numbers = (5, 1, 4, 2, 3)
sorted_numbers = sorted(numbers)
print(sorted_numbers)
# Output: [1, 2, 3, 4, 5]
sorted()
can sort any iterable object, including tuples which normally cannot be modified.
One important point is that sorted()
does not modify the original object - it returns a new sorted object instead. So the original list or tuple remains unchanged.
Custom Sorting with key Parameter
To customize how the elements are sorted, we can use the key
parameter to provide a function that transforms each element before comparing them.
For example, to sort a list of strings ignoring case:
names = ["John", "mark", "tom", "Amanda"]
sorted_names = sorted(names, key=str.lower)
print(sorted_names)
# Output: ['Amanda', 'John', 'mark', 'tom']
Here we pass the str.lower
function as the key which converts each name to lower case before comparing them. This results in a case-insensitive sorting.
The key
function takes in a single element and returns a value to be used for comparisons in sorting. This allows powerful flexibility to customize sorting order.
Some more examples:
# Sort list of tuples by second item
tuples = [(1, 4), (3, 7), (2, 5)]
sorted_tuples = sorted(tuples, key=lambda x: x[1])
print(sorted_tuples)
# Output: [(1, 4), (2, 5), (3, 7)]
# Sort strings by length
strings = ["Python", "Java", "C++", "Rust"]
sorted_strings = sorted(strings, key=len)
print(sorted_strings)
# Output: ['C++', 'Java', 'Python', 'Rust']
The key
function provides unlimited possibilities for advanced sorting logic.
Sorting in Reverse
To sort the elements in reverse or descending order, we can set the reverse
flag to True
.
numbers = [5, 1, 4, 3, 2]
sorted_numbers = sorted(numbers, reverse=True)
print(sorted_numbers)
# Output: [5, 4, 3, 2, 1]
The reverse
flag tells sorted()
to reverse the comparisons while sorting the elements.
We can combine reverse=True
with a custom key
function to get a descending order with custom sorting logic.
Complexity
The sorted()
function has a time complexity of O(n log n) - efficient even for large lists.
In summary, sorted()
is ideal when:
- You need to get a new sorted list but keep the original intact.
- You want to sort an iterable like tuple or string.
- You need custom or complex sorting order.
- Efficiency for large lists is important.
Next, let’s see how to sort a list in-place.
The list.sort() Method
For mutating sorting that changes the original list object, we can use the list.sort()
method.
Syntax
list.sort(key=None, reverse=False)
key
(optional) - Custom sort order functionreverse
(optional) - To sort in descending order ifTrue
Example Usage
numbers = [5, 1, 4, 2, 3]
numbers.sort()
print(numbers)
# Output: [1, 2, 3, 4, 5]
Unlike sorted()
, list.sort()
sorts the list in-place and does not return anything. The original list is permanently changed into the sorted order.
Let’s see a few more examples:
names = ["John", "mark", "tom", "Amanda"]
names.sort(key=str.lower)
print(names)
# Output: ['Amanda', 'John', 'mark', 'tom']
products = [('Banana', 1), ('Orange', 5), ('Apple', 4)]
products.sort(key=lambda x: x[1])
print(products)
# Output: [('Banana', 1), ('Apple', 4), ('Orange', 5)]
We can use key
and reverse
similar to sorted()
to customize sorting logic.
Complexity
The .sort()
method has worst case time complexity of O(n log n) - efficient for large lists.
In summary, list.sort()
is ideal when:
- You want to mutate the list by sorting it in-place.
- You need efficiency for large lists.
- You want to avoid creating new list objects.
Now let’s look at how to leverage these techniques to sort some real-world examples.
Practical Examples of Sorting Lists in Python
Let’s go through some practical code examples of sorting common list data types in Python.
Example 1: Sort a List of Integers
numbers = [15, 6, 18, 2, 45, 10, 8]
# Ascending order
numbers.sort()
print(numbers)
# Output: [2, 6, 8, 10, 15, 18, 45]
# Descending order
numbers.sort(reverse=True)
print(numbers)
# Output: [45, 18, 15, 10, 8, 6, 2]
To sort integers we can simply use the default natural ordering.
Example 2: Sort a List of Strings
names = ["Mark", "john", "tom", "Amanda", "Ron"]
# Ascending case-insensitive order
names.sort(key=str.lower)
print(names)
# Output: ['Amanda', 'john', 'Mark', 'Ron', 'tom']
# Descending case-sensitive order
names.sort(key=str.lower, reverse=True)
print(names)
# Output: ['tom', 'Ron', 'Mark', 'john', 'Amanda']
For strings, we used str.lower
as key for case-insensitive sorting.
Example 3: Sort a List of Tuples
products = [('Apple', 200), ('Orange', 160), ('Banana', 50)]
# Sort by price ascending
products.sort(key=lambda x: x[1])
print(products)
# Output: [('Banana', 50), ('Orange', 160), ('Apple', 200)]
# Sort by name descending
products.sort(key=lambda x: x[0], reverse=True)
print(products)
# Output: [('Orange', 160), ('Banana', 50), ('Apple', 200)]
For tuples, we used a lambda
key function to access the indexed item to sort by.
Example 4: Sort a List of Dicts
employees = [
{'Name': 'John', 'Age': 28},
{'Name': 'Jane', 'Age': 30},
{'Name': 'Jack', 'Age': 26}
]
# Sort by Age ascending
employees.sort(key=lambda x: x['Age'])
print(employees)
# Output: [{'Name': 'Jack', 'Age': 26},
{'Name': 'John', 'Age': 28},
{'Name': 'Jane', 'Age': 30}]
# Sort by Name descending
employees.sort(key=lambda x: x['Name'], reverse=True)
print(employees)
# Output: [{'Name': 'John', 'Age': 28},
{'Name': 'Jack', 'Age': 26},
{'Name': 'Jane', 'Age': 30}]
For dictionaries, we passed a lambda to access the value of the desired key for sorting.
Example 5: Sort a List of Objects
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
people = [
Person('John', 28),
Person('Jack', 26),
Person('Jane', 30)
]
# Sort by age
people.sort(key=lambda x: x.age)
print(people)
# Output: [Person('Jack', 26), Person('John', 28), Person('Jane', 30)]
# Sort by name descending
people.sort(key=lambda x: x.name, reverse=True)
print(people)
# Output: [Person('John', 28), Person('Jack', 26), Person('Jane', 30)]
For custom class objects, we access the attributes inside the lambda function to define sorting logic.
These examples demonstrate how we can sort common Python data types in practice.
Conclusion
In summary, Python provides highly efficient and flexible ways to sort lists using sorted()
, list.sort()
, and custom key
functions.
The key takeaways are:
-
sorted()
returns a new sorted list copy leaving the original unchanged. -
list.sort()
sorts the list in-place mutating the original. -
Use
key
to customize sorting logic by transforming elements before comparing. -
Set
reverse=True
to sort in descending order. -
Sorting has O(n log n) time complexity - efficient for large datasets.
-
Leverage these tools to sort integers, strings, tuples, dicts, objects, and more.
With this comprehensive guide, you should feel confident applying these techniques for sorting tasks in Python coding and data analysis. The built-in sorting functionality makes it easy to work with sorted data.
Happy Python coding!