@@ -785,8 +785,8 @@ well as with the built-in itertools such as ``map()``, ``filter()``,
785785
786786A secondary purpose of the recipes is to serve as an incubator. The
787787``accumulate() ``, ``compress() ``, and ``pairwise() `` itertools started out as
788- recipes. Currently, the ``sliding_window() `` and ``iter_index() `` recipes
789- are being tested to see whether they prove their worth.
788+ recipes. Currently, the ``sliding_window() ``, ``iter_index() ``, and `` sieve() ``
789+ recipes are being tested to see whether they prove their worth.
790790
791791Substantially all of these recipes and many, many others can be installed from
792792the `more-itertools project <https://pypi.org/project/more-itertools/ >`_ found
@@ -795,12 +795,12 @@ on the Python Package Index::
795795 python -m pip install more-itertools
796796
797797Many of the recipes offer the same high performance as the underlying toolset.
798- Superior memory performance is kept by processing elements one at a time
799- rather than bringing the whole iterable into memory all at once. Code volume is
800- kept small by linking the tools together in a functional style which helps
801- eliminate temporary variables. High speed is retained by preferring
802- "vectorized" building blocks over the use of for-loops and :term: ` generator ` \s
803- which incur interpreter overhead.
798+ Superior memory performance is kept by processing elements one at a time rather
799+ than bringing the whole iterable into memory all at once. Code volume is kept
800+ small by linking the tools together in a ` functional style
801+ <https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf> `_. High speed
802+ is retained by preferring "vectorized" building blocks over the use of for-loops
803+ and :term: ` generators <generator> ` which incur interpreter overhead.
804804
805805.. testcode ::
806806
@@ -873,6 +873,14 @@ which incur interpreter overhead.
873873 "Returns True if all the elements are equal to each other."
874874 return len(take(2, groupby(iterable, key))) <= 1
875875
876+ def unique_justseen(iterable, key=None):
877+ "List unique elements, preserving order. Remember only the element just seen."
878+ # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
879+ # unique_justseen('ABBcCAD', str.casefold) --> A B c A D
880+ if key is None:
881+ return map(operator.itemgetter(0), groupby(iterable))
882+ return map(next, map(operator.itemgetter(1), groupby(iterable, key)))
883+
876884 def unique_everseen(iterable, key=None):
877885 "List unique elements, preserving order. Remember all elements ever seen."
878886 # unique_everseen('AAAABBBCCDAABBB') --> A B C D
@@ -889,35 +897,6 @@ which incur interpreter overhead.
889897 seen.add(k)
890898 yield element
891899
892- def unique_justseen(iterable, key=None):
893- "List unique elements, preserving order. Remember only the element just seen."
894- # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
895- # unique_justseen('ABBcCAD', str.casefold) --> A B c A D
896- if key is None:
897- return map(operator.itemgetter(0), groupby(iterable))
898- return map(next, map(operator.itemgetter(1), groupby(iterable, key)))
899-
900- def iter_index(iterable, value, start=0, stop=None):
901- "Return indices where a value occurs in a sequence or iterable."
902- # iter_index('AABCADEAF', 'A') --> 0 1 4 7
903- seq_index = getattr(iterable, 'index', None)
904- if seq_index is None:
905- # Path for general iterables
906- it = islice(iterable, start, stop)
907- for i, element in enumerate(it, start):
908- if element is value or element == value:
909- yield i
910- else:
911- # Path for sequences with an index() method
912- stop = len(iterable) if stop is None else stop
913- i = start
914- try:
915- while True:
916- yield (i := seq_index(value, i, stop))
917- i += 1
918- except ValueError:
919- pass
920-
921900 def sliding_window(iterable, n):
922901 "Collect data into overlapping fixed-length chunks or blocks."
923902 # sliding_window('ABCDEFG', 4) --> ABCD BCDE CDEF DEFG
@@ -967,6 +946,27 @@ which incur interpreter overhead.
967946 slices = starmap(slice, combinations(range(len(seq) + 1), 2))
968947 return map(operator.getitem, repeat(seq), slices)
969948
949+ def iter_index(iterable, value, start=0, stop=None):
950+ "Return indices where a value occurs in a sequence or iterable."
951+ # iter_index('AABCADEAF', 'A') --> 0 1 4 7
952+ seq_index = getattr(iterable, 'index', None)
953+ if seq_index is None:
954+ # Path for general iterables
955+ it = islice(iterable, start, stop)
956+ for i, element in enumerate(it, start):
957+ if element is value or element == value:
958+ yield i
959+ else:
960+ # Path for sequences with an index() method
961+ stop = len(iterable) if stop is None else stop
962+ i = start
963+ try:
964+ while True:
965+ yield (i := seq_index(value, i, stop))
966+ i += 1
967+ except ValueError:
968+ pass
969+
970970 def iter_except(func, exception, first=None):
971971 """ Call a function repeatedly until an exception is raised.
972972
@@ -1047,8 +1047,8 @@ The following recipes have a more mathematical flavor:
10471047
10481048 Computes with better numeric stability than Horner's method.
10491049 """
1050- # Evaluate x³ -4x² -17x + 60 at x = 2. 5
1051- # polynomial_eval([1, -4, -17, 60], x=2. 5) --> 8.125
1050+ # Evaluate x³ -4x² -17x + 60 at x = 5
1051+ # polynomial_eval([1, -4, -17, 60], x=5) --> 0
10521052 n = len(coefficients)
10531053 if not n:
10541054 return type(x)(0)
@@ -1311,10 +1311,10 @@ The following recipes have a more mathematical flavor:
13111311
13121312 >>> from fractions import Fraction
13131313 >>> from decimal import Decimal
1314- >>> polynomial_eval([1 , - 4 , - 17 , 60 ], x = 2 )
1315- 18
1316- >>> x = 2 ; x** 3 - 4 * x** 2 - 17 * x + 60
1317- 18
1314+ >>> polynomial_eval([1 , - 4 , - 17 , 60 ], x = 5 )
1315+ 0
1316+ >>> x = 5 ; x** 3 - 4 * x** 2 - 17 * x + 60
1317+ 0
13181318 >>> polynomial_eval([1 , - 4 , - 17 , 60 ], x = 2.5 )
13191319 8.125
13201320 >>> x = 2.5 ; x** 3 - 4 * x** 2 - 17 * x + 60
0 commit comments