From ebacc5b8569b57b227063275d25892d58cd68290 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Thu, 22 Feb 2024 00:41:13 -0600 Subject: [PATCH 1/6] Add link to casefold() --- Doc/howto/sorting.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst index b98f91e023bdfc..05ee6b217a8545 100644 --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -51,7 +51,8 @@ Both :meth:`list.sort` and :func:`sorted` have a *key* parameter to specify a function (or other callable) to be called on each list element prior to making comparisons. -For example, here's a case-insensitive string comparison: +For example, here's a case-insensitive string comparison using +:meth:`str.casefold`: .. doctest:: From ff950c112025458999286cff3655a8a4b1e702e9 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Thu, 22 Feb 2024 03:02:45 -0600 Subject: [PATCH 2/6] Add strategies for type and value issues --- Doc/howto/sorting.rst | 65 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst index 05ee6b217a8545..97a5098ca43424 100644 --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -273,6 +273,71 @@ to make it usable as a key function:: sorted(words, key=cmp_to_key(strcoll)) # locale-aware sort order +Strategies For Unorderable Types and Values +=========================================== + +A number of type and value issues can arise when sorting. +Here are some strategies that can help: + +* Convert inputs to strings prior to sorting: + +.. doctest:: + + >>> data = ['twelve', '11', 10] + >>> sorted(map(str, data)) + ['10', '11', 'twelve'] + +This is needed because most cross-type comparisons raise a +:exc:`TypeError`. + +* Remove special values prior to sorting: + +.. doctest:: + + >>> from math import isnan + >>> from itertools import filterfalse + >>> data = [3.3, float('nan'), 1.1, 2.2] + >>> sorted(filterfalse(isnan, data)) + [1.1, 2.2, 3.3] + +This is needed because the `IEEE-754 standard +`_ specifies that, "Every NaN +shall compare unordered with everything, including itself." + +Likewise, ``None`` can be stripped from datasets as well: + +.. doctest:: + + >>> data = [3.3, None, 1.1, 2.2] + >>> sorted(x for x in data if x is not None) + [1.1, 2.2, 3.3] + +This is needed because ``None`` is not comparable to other types. + +* Convert mapping types into sortable items before sorting: + +.. doctest:: + + >>> from operator import methodcaller + >>> data = [{'a': 1}, {'b': 2}] + >>> list(map(dict, sorted(map(methodcaller('items'), data)))) + [{'a': 1}, {'b': 2}] + +This is needed because dict-to-dict comparisons raise a +:exc:`TypeError`. + +* Convert set types into sorted lists before sorting: + +.. doctest:: + + >>> data = [{'a', 'b', 'c'}, {'b', 'c', 'd'}] + >>> sorted(map(sorted, data)) + [['a', 'b', 'c'], ['b', 'c', 'd']] + +This is needed because the elements contained in set types do not have a +deterministic order. For example, ``list({'a', 'b'})`` may produce +either ``['a', 'b']`` or ``['b', 'a']``. + Odds and Ends ============= From 9eace430acfc6dfd89e8a8ed35c855ba2262f834 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Thu, 22 Feb 2024 03:16:31 -0600 Subject: [PATCH 3/6] Note key-function support in other functions --- Doc/howto/sorting.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst index 97a5098ca43424..d99a78e780c816 100644 --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -47,8 +47,10 @@ lists. In contrast, the :func:`sorted` function accepts any iterable. Key Functions ============= -Both :meth:`list.sort` and :func:`sorted` have a *key* parameter to specify a -function (or other callable) to be called on each list element prior to making +This :meth:`list.sort` method and the functions :func:`sorted`, +:func:`min`, :func:`max`, :func:`heapq.nsmallest`, and +:func:`heapq.nlargest` have a *key* parameter to specify a function (or +other callable) to be called on each list element prior to making comparisons. For example, here's a case-insensitive string comparison using From 5a344bed709ca6f7646f3485b4f0a305cc20ed52 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Fri, 27 Sep 2024 12:02:36 -0700 Subject: [PATCH 4/6] minor edits --- Doc/howto/sorting.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst index d99a78e780c816..39da88c0738ff5 100644 --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -281,7 +281,7 @@ Strategies For Unorderable Types and Values A number of type and value issues can arise when sorting. Here are some strategies that can help: -* Convert inputs to strings prior to sorting: +* Convert non-comparable input types to strings prior to sorting: .. doctest:: @@ -316,7 +316,7 @@ Likewise, ``None`` can be stripped from datasets as well: This is needed because ``None`` is not comparable to other types. -* Convert mapping types into sortable items before sorting: +* Convert mapping types into sorted item lists before sorting: .. doctest:: From 0102000ccf17b968d769457aa7b13d56a71c5fe2 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Fri, 27 Sep 2024 13:07:49 -0700 Subject: [PATCH 5/6] Update Doc/howto/sorting.rst Co-authored-by: Pieter Eendebak --- Doc/howto/sorting.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst index 39da88c0738ff5..3f316dd53a39db 100644 --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -47,7 +47,7 @@ lists. In contrast, the :func:`sorted` function accepts any iterable. Key Functions ============= -This :meth:`list.sort` method and the functions :func:`sorted`, +The :meth:`list.sort` method and the functions :func:`sorted`, :func:`min`, :func:`max`, :func:`heapq.nsmallest`, and :func:`heapq.nlargest` have a *key* parameter to specify a function (or other callable) to be called on each list element prior to making From 5c3a3121e9c9ea9c8243025c923fd603acc6165f Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Fri, 27 Sep 2024 15:56:47 -0700 Subject: [PATCH 6/6] Sort the items() --- Doc/howto/sorting.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/howto/sorting.rst b/Doc/howto/sorting.rst index 3f316dd53a39db..70c34cde8a0659 100644 --- a/Doc/howto/sorting.rst +++ b/Doc/howto/sorting.rst @@ -320,9 +320,8 @@ This is needed because ``None`` is not comparable to other types. .. doctest:: - >>> from operator import methodcaller >>> data = [{'a': 1}, {'b': 2}] - >>> list(map(dict, sorted(map(methodcaller('items'), data)))) + >>> sorted(data, key=lambda d: sorted(d.items())) [{'a': 1}, {'b': 2}] This is needed because dict-to-dict comparisons raise a