Skip to content

Commit 9f8a9e8

Browse files
authored
Modernize the Sorting HowTo guide (gh-115479)
1 parent c2cb31b commit 9f8a9e8

File tree

1 file changed

+54
-6
lines changed

1 file changed

+54
-6
lines changed

Doc/howto/sorting.rst

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ Sorting HOW TO
44
**************
55

66
:Author: Andrew Dalke and Raymond Hettinger
7-
:Release: 0.1
87

98

109
Python lists have a built-in :meth:`list.sort` method that modifies the list
@@ -56,7 +55,7 @@ For example, here's a case-insensitive string comparison:
5655

5756
.. doctest::
5857

59-
>>> sorted("This is a test string from Andrew".split(), key=str.lower)
58+
>>> sorted("This is a test string from Andrew".split(), key=str.casefold)
6059
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']
6160

6261
The value of the *key* parameter should be a function (or other callable) that
@@ -97,10 +96,14 @@ The same technique works for objects with named attributes. For example:
9796
>>> sorted(student_objects, key=lambda student: student.age) # sort by age
9897
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
9998

100-
Operator Module Functions
101-
=========================
99+
Objects with named attributes can be made by a regular class as shown
100+
above, or they can be instances of :class:`~dataclasses.dataclass` or
101+
a :term:`named tuple`.
102102

103-
The key-function patterns shown above are very common, so Python provides
103+
Operator Module Functions and Partial Function Evaluation
104+
=========================================================
105+
106+
The :term:`key function` patterns shown above are very common, so Python provides
104107
convenience functions to make accessor functions easier and faster. The
105108
:mod:`operator` module has :func:`~operator.itemgetter`,
106109
:func:`~operator.attrgetter`, and a :func:`~operator.methodcaller` function.
@@ -128,6 +131,24 @@ sort by *grade* then by *age*:
128131
>>> sorted(student_objects, key=attrgetter('grade', 'age'))
129132
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
130133

134+
The :mod:`functools` module provides another helpful tool for making
135+
key-functions. The :func:`~functools.partial` function can reduce the
136+
`arity <https://en.wikipedia.org/wiki/Arity>`_ of a multi-argument
137+
function making it suitable for use as a key-function.
138+
139+
.. doctest::
140+
141+
>>> from functools import partial
142+
>>> from unicodedata import normalize
143+
144+
>>> names = 'Zoë Åbjørn Núñez Élana Zeke Abe Nubia Eloise'.split()
145+
146+
>>> sorted(names, key=partial(normalize, 'NFD'))
147+
['Abe', 'Åbjørn', 'Eloise', 'Élana', 'Nubia', 'Núñez', 'Zeke', 'Zoë']
148+
149+
>>> sorted(names, key=partial(normalize, 'NFC'))
150+
['Abe', 'Eloise', 'Nubia', 'Núñez', 'Zeke', 'Zoë', 'Åbjørn', 'Élana']
151+
131152
Ascending and Descending
132153
========================
133154

@@ -200,6 +221,8 @@ This idiom is called Decorate-Sort-Undecorate after its three steps:
200221

201222
For example, to sort the student data by *grade* using the DSU approach:
202223

224+
.. doctest::
225+
203226
>>> decorated = [(student.grade, i, student) for i, student in enumerate(student_objects)]
204227
>>> decorated.sort()
205228
>>> [student for grade, i, student in decorated] # undecorate
@@ -282,7 +305,11 @@ Odds and Ends
282305
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
283306

284307
However, note that ``<`` can fall back to using :meth:`~object.__gt__` if
285-
:meth:`~object.__lt__` is not implemented (see :func:`object.__lt__`).
308+
:meth:`~object.__lt__` is not implemented (see :func:`object.__lt__`
309+
for details on the mechanics). To avoid surprises, :pep:`8`
310+
recommends that all six comparison methods be implemented.
311+
The :func:`~functools.total_ordering` decorator is provided to make that
312+
task easier.
286313

287314
* Key functions need not depend directly on the objects being sorted. A key
288315
function can also access external resources. For instance, if the student grades
@@ -295,3 +322,24 @@ Odds and Ends
295322
>>> newgrades = {'john': 'F', 'jane':'A', 'dave': 'C'}
296323
>>> sorted(students, key=newgrades.__getitem__)
297324
['jane', 'dave', 'john']
325+
326+
Partial Sorts
327+
=============
328+
329+
Some applications require only some of the data to be ordered. The standard
330+
library provides several tools that do less work than a full sort:
331+
332+
* :func:`min` and :func:`max` return the smallest and largest values,
333+
respectively. These functions make a single pass over the input data and
334+
require almost no auxiliary memory.
335+
336+
* :func:`heapq.nsmallest` and :func:`heapq.nlargest` return
337+
the *n* smallest and largest values, respectively. These functions
338+
make a single pass over the data keeping only *n* elements in memory
339+
at a time. For values of *n* that are small relative to the number of
340+
inputs, these functions make far fewer comparisons than a full sort.
341+
342+
* :func:`heapq.heappush` and :func:`heapq.heappop` create and maintain a
343+
partially sorted arrangement of data that keeps the smallest element
344+
at position ``0``. These functions are suitable for implementing
345+
priority queues which are commonly used for task scheduling.

0 commit comments

Comments
 (0)