From 804983f3ac5c84998c878fa2f5ce3be9bf1c3b3b Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 1 Jun 2024 10:34:06 -0500 Subject: [PATCH 1/2] Add unique() recipe to itertools docs --- Doc/library/itertools.rst | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 121bfd3de343c4..0c38af570772f3 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -857,7 +857,7 @@ and :term:`generators ` which incur interpreter overhead. return len(take(2, groupby(iterable, key))) <= 1 def unique_justseen(iterable, key=None): - "List unique elements, preserving order. Remember only the element just seen." + "Yield unique elements, preserving order. Remember only the element just seen." # unique_justseen('AAAABBBCCDAABBB') → A B C D A B # unique_justseen('ABBcCAD', str.casefold) → A B c A D if key is None: @@ -865,7 +865,7 @@ and :term:`generators ` which incur interpreter overhead. return map(next, map(operator.itemgetter(1), groupby(iterable, key))) def unique_everseen(iterable, key=None): - "List unique elements, preserving order. Remember all elements ever seen." + "Yield unique elements, preserving order. Remember all elements ever seen." # unique_everseen('AAAABBBCCDAABBB') → A B C D # unique_everseen('ABBcCAD', str.casefold) → A B c D seen = set() @@ -880,6 +880,11 @@ and :term:`generators ` which incur interpreter overhead. seen.add(k) yield element + def unique(iterable, key=None): + "Yield unique elements in sorted order. Supports unhashable inputs." + # unique([[1, 2], [3, 4], [1, 2]]) → [1, 2] [3, 4] + return unique_justseen(sorted(iterable, key=key), key=key) + def sliding_window(iterable, n): "Collect data into overlapping fixed-length chunks or blocks." # sliding_window('ABCDEFG', 4) → ABCD BCDE CDEF DEFG @@ -1605,6 +1610,11 @@ The following recipes have a more mathematical flavor: >>> ''.join(input_iterator) 'AAABBBCCDAABBB' + >>> list(unique([[1, 2], [3, 4], [1, 2]])) + [[1, 2], [3, 4]] + >>> list(unique('ABBcCAD', str.casefold)) + ['A', 'B', 'c', 'D'] + >>> d = dict(a=1, b=2, c=3) >>> it = iter_except(d.popitem, KeyError) >>> d['d'] = 4 From b87dc8ba8d9b3bf577c6d1e4f836838cc83a6684 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 1 Jun 2024 11:09:56 -0500 Subject: [PATCH 2/2] Support the "reverse" flag --- Doc/library/itertools.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 0c38af570772f3..3dc3f60923a0ba 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -880,10 +880,10 @@ and :term:`generators ` which incur interpreter overhead. seen.add(k) yield element - def unique(iterable, key=None): + def unique(iterable, key=None, reverse=False): "Yield unique elements in sorted order. Supports unhashable inputs." # unique([[1, 2], [3, 4], [1, 2]]) → [1, 2] [3, 4] - return unique_justseen(sorted(iterable, key=key), key=key) + return unique_justseen(sorted(iterable, key=key, reverse=reverse), key=key) def sliding_window(iterable, n): "Collect data into overlapping fixed-length chunks or blocks." @@ -1614,6 +1614,8 @@ The following recipes have a more mathematical flavor: [[1, 2], [3, 4]] >>> list(unique('ABBcCAD', str.casefold)) ['A', 'B', 'c', 'D'] + >>> list(unique('ABBcCAD', str.casefold, reverse=True)) + ['D', 'c', 'B', 'A'] >>> d = dict(a=1, b=2, c=3) >>> it = iter_except(d.popitem, KeyError)