Sorting
Python provides two built-in functions for sorting:
list.sort()
: modifies the list in-placesorted()
: builds a new sorted list from an iterable
Difference between these methods:
list.sort()
method is only defined for lists. In contrast, thesorted()
function accepts any iterable.list.sort()
modifies the list in-place and returnsNone
.sorted()
returns a new sorted list. Usuallysort()
is less convenient thansorted()
.
Sorting Basics
A simple ascending sort is very easy: just call the sorted()
function. It returns a new sorted list.
Example
>>> a = [5, 2, 1, 3, 4]
>>> b = sorted(a)
>>> a # the original list is not affected
[5, 2, 1, 3, 4]
>>> b
[1, 2, 3, 4, 5]
Key
Both list.sort()
and sorted()
have a key
parameter.
The value of the key
parameter should be a function (or other callable) that serves as a key for the sort comparison. In other word, key
decides the comparison criteria for sorting.
One way to specify key
is to use the lambda function.
Example:
students_dict = [
{"name": "John", "age": 12, "grade": "A"},
{"name": "Mary", "age": 14, "grade": "B"},
{"name": "Ben", "age": 13, "grade": "A"}
]
sorted(students_dict, key=lambda student: student.get("age")) # sort by age
Output:
[{'age': 12, 'grade': 'A', 'name': 'John'},
{'age': 13, 'grade': 'A', 'name': 'Ben'},
{'age': 14, 'grade': 'B', 'name': 'Mary'}]
This also works for objects with named attributes.
Example:
class Student:
def __init__(self, name, age, grade):
self.name = name
self.age = age
self.grade = grade
def __repr__(self):
return repr((self.name, self.age, self.grade))
students = [
Student("John", 12, "A"),
Student("Mary", 14, "B"),
Student("Ben", 13, "A")
]
sorted(students, key=lambda student: student.age)
Output:
[('John', 12, 'A'), ('Ben', 13, 'A'), ('Mary', 14, 'B')]
Operator Module Functions
Python operator
module provides convenience functions to make accessor functions easier and faster:
itemgetter()
attrgetter()
methodcaller()
itemgetter()
Example:
students_tuple = [
("John", 12, "A"),
("Mary", 14, "B"),
("Ben", 13, "A")
]
sorted(students_tuple, key=itemgetter(1))
Output:
[('John', 12, 'A'), ('Ben', 13, 'A'), ('Mary', 14, 'B')]
students_dict = [
{"name": "John", "age": 12, "grade": "A"},
{"name": "Mary", "age": 14, "grade": "B"},
{"name": "Ben", "age": 13, "grade": "A"}
]
sorted(students_dict, key=itemgetter("age"))
Output:
[{'age': 12, 'grade': 'A', 'name': 'John'},
{'age': 13, 'grade': 'A', 'name': 'Ben'},
{'age': 14, 'grade': 'B', 'name': 'Mary'}]
attrgetter()
Example:
class Student:
def __init__(self, name, age, grade):
self.name = name
self.age = age
self.grade = grade
def __repr__(self):
return repr((self.name, self.age, self.grade))
students = [
Student("John", 12, "A"),
Student("Mary", 14, "B"),
Student("Ben", 13, "A")
]
[('John', 12, 'A'), ('Ben', 13, 'A'), ('Mary', 14, 'B')]
order
Both list.sort()
and sorted()
accept a reverse parameter with a boolean value. This is used to flag descending sorts" reverse=False
and reverse=True
represent ascending and descening order, respectively.
Advance
Multiple levels of sorting
Multiple level of sorting can be easily achieved with operator module functions.
For example, to sort by grade
then by age
:
>>> sorted(students_tuple, key=itemgetter(2, 1))
[('John', 12, 'A'), ('Ben', 13, 'A'), ('Mary', 14, 'B')]
>>> sorted(students, key=attrgetter("grade", "age"))
[('John', 12, 'A'), ('Ben', 13, 'A'), ('Mary', 14, 'B')]
>>> sorted(students_dict, key=itemgetter("grade", "age"))
[{'age': 12, 'grade': 'A', 'name': 'John'},
{'age': 13, 'grade': 'A', 'name': 'Ben'},
{'age': 14, 'grade': 'B', 'name': 'Mary'}]