python sorted function

Sorted function is a great function in my study process and when I learning python, I’ve used it so many times, today, let me conclude some usage of this function.

sorted function#

Basics#

Ascending sorting:

1
2
3
4
5
sorted([5, 2, 3, 1, 4])

# also can use list.sort()
a = [5, 2, 3, 1, 4]
a.sort()

the sorted() function accepts any iterable:

1
2
>>> sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'})
[1, 2, 3, 4, 5]

Key functions#

The key parameter to specify a function (or other callable) to be called on each list element prior to making comparisons:

1
2
>>> sorted("This is a test string from Andrew".split(), key=str.lower)
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']

The key should be a function or any callable.

Another examples:

1
2
3
4
5
6
7
>>> student_tuples = [
... ('john', 'A', 15),
... ('jane', 'B', 12),
... ('dave', 'B', 10),
... ]
>>> sorted(student_tuples, key=lambda student: student[2]) # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

Sort a dict by value:

1
2
3
 x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> dict(sorted(x.items(), key=lambda item: item[1]))
{0: 0, 2: 1, 1: 2, 4: 3, 3: 4}

The same technique works for objects with named attributes. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Student:
def __init__(self, name, grade, age):
self.name = name
self.grade = grade
self.age = age
def __repr__(self):
return repr((self.name, self.grade, self.age))

student_objects = [
Student('john', 'A', 15),
Student('jane', 'B', 12),
Student('dave', 'B', 10),
]
sorted(student_objects, key=lambda student: student.age) # sort by age

Operator Module Function#

The key-function patterns shown above are very common, so Python provides convenience functions to make accessor functions easier and faster. The operator module has itemgetter(), attrgetter(), and a methodcaller() function.

1
2
3
4
5
6
7
8
>>> from operator import itemgetter, attrgetter

>>> sorted(student_tuples, key=itemgetter(2))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

# to the student class
>>> sorted(student_objects, key=attrgetter('age'))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

The operator module functions allow multiple levels of sorting. For example, to sort by grade then by age:

1
2
3
4
5
>>> sorted(student_tuples, key=itemgetter(1,2))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]

>>> sorted(student_objects, key=attrgetter('grade', 'age'))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]

You can use reverse=True to flag descending sorts:

1
2
3
4
5
>>> sorted(student_tuples, key=itemgetter(2), reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

>>> sorted(student_objects, key=attrgetter('age'), reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

Sort Stability and Complex Sorts#

From Wikipedia, the definition of sorting stability is:

Stable sort algorithms sort equal elements in the same order that they appear in the input.

For example, Stable sorting algorithms choose one of these, according to the following rule: if two items compare as equal, then their relative order will be preserved, i.e. if one comes before the other in the input, it will come before the other in the output.

In Sorted, Sorts are guaranteed to be stable.

1
2
3
>>> data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
>>> sorted(data, key=itemgetter(0))
[('blue', 1), ('blue', 2), ('red', 1), ('red', 2)]

Notice how the two records for blue retain their original order so that ('blue', 1) is guaranteed to precede ('blue', 2).

You can build complex sorts in a series of sorting steps. For example, to sort the student data by descending grade and then ascending age, do the age sort first and then sort again using grade:

1
2
3
>>> s = sorted(student_objects, key=attrgetter('age'))     # sort on secondary key
>>> sorted(s, key=attrgetter('grade'), reverse=True) # now sort on primary key, descending
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]