@@ -30,11 +30,6 @@ For instance, SML provides a tabulation tool: ``tabulate(f)`` which produces a
30
30
sequence ``f(0), f(1), ... ``. The same effect can be achieved in Python
31
31
by combining :func: `map ` and :func: `count ` to form ``map(f, count()) ``.
32
32
33
- These tools and their built-in counterparts also work well with the high-speed
34
- functions in the :mod: `operator ` module. For example, the multiplication
35
- operator can be mapped across two vectors to form an efficient dot-product:
36
- ``sum(starmap(operator.mul, zip(vec1, vec2, strict=True))) ``.
37
-
38
33
39
34
**Infinite iterators: **
40
35
@@ -686,7 +681,7 @@ loops that truncate the stream.
686
681
consumed from the input iterator and there is no way to access it.
687
682
This could be an issue if an application wants to further consume the
688
683
input iterator after *takewhile * has been run to exhaustion. To work
689
- around this problem, consider using `more-iterools before_and_after()
684
+ around this problem, consider using `more-itertools before_and_after()
690
685
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.before_and_after> `_
691
686
instead.
692
687
@@ -843,12 +838,11 @@ and :term:`generators <generator>` which incur interpreter overhead.
843
838
844
839
.. testcode ::
845
840
846
- import collections
847
- import contextlib
848
- import functools
849
- import math
850
- import operator
851
- import random
841
+ from collections import deque
842
+ from contextlib import suppress
843
+ from functools import reduce
844
+ from math import sumprod, isqrt
845
+ from operator import itemgetter, getitem, mul, neg
852
846
853
847
def take(n, iterable):
854
848
"Return first n items of the iterable as a list."
@@ -863,11 +857,11 @@ and :term:`generators <generator>` which incur interpreter overhead.
863
857
"Return function(0), function(1), ..."
864
858
return map(function, count(start))
865
859
866
- def repeatfunc(func , times=None, *args):
867
- "Repeat calls to func with specified arguments."
860
+ def repeatfunc(function , times=None, *args):
861
+ "Repeat calls to a function with specified arguments."
868
862
if times is None:
869
- return starmap(func , repeat(args))
870
- return starmap(func , repeat(args, times))
863
+ return starmap(function , repeat(args))
864
+ return starmap(function , repeat(args, times))
871
865
872
866
def flatten(list_of_lists):
873
867
"Flatten one level of nesting."
@@ -885,13 +879,13 @@ and :term:`generators <generator>` which incur interpreter overhead.
885
879
def tail(n, iterable):
886
880
"Return an iterator over the last n items."
887
881
# tail(3, 'ABCDEFG') → E F G
888
- return iter(collections. deque(iterable, maxlen=n))
882
+ return iter(deque(iterable, maxlen=n))
889
883
890
884
def consume(iterator, n=None):
891
885
"Advance the iterator n-steps ahead. If n is None, consume entirely."
892
886
# Use functions that consume iterators at C speed.
893
887
if n is None:
894
- collections. deque(iterator, maxlen=0)
888
+ deque(iterator, maxlen=0)
895
889
else:
896
890
next(islice(iterator, n, n), None)
897
891
@@ -919,8 +913,8 @@ and :term:`generators <generator>` which incur interpreter overhead.
919
913
# unique_justseen('AAAABBBCCDAABBB') → A B C D A B
920
914
# unique_justseen('ABBcCAD', str.casefold) → A B c A D
921
915
if key is None:
922
- return map(operator. itemgetter(0), groupby(iterable))
923
- return map(next, map(operator. itemgetter(1), groupby(iterable, key)))
916
+ return map(itemgetter(0), groupby(iterable))
917
+ return map(next, map(itemgetter(1), groupby(iterable, key)))
924
918
925
919
def unique_everseen(iterable, key=None):
926
920
"Yield unique elements, preserving order. Remember all elements ever seen."
@@ -941,13 +935,14 @@ and :term:`generators <generator>` which incur interpreter overhead.
941
935
def unique(iterable, key=None, reverse=False):
942
936
"Yield unique elements in sorted order. Supports unhashable inputs."
943
937
# unique([[1, 2], [3, 4], [1, 2]]) → [1, 2] [3, 4]
944
- return unique_justseen(sorted(iterable, key=key, reverse=reverse), key=key)
938
+ sequenced = sorted(iterable, key=key, reverse=reverse)
939
+ return unique_justseen(sequenced, key=key)
945
940
946
941
def sliding_window(iterable, n):
947
942
"Collect data into overlapping fixed-length chunks or blocks."
948
943
# sliding_window('ABCDEFG', 4) → ABCD BCDE CDEF DEFG
949
944
iterator = iter(iterable)
950
- window = collections. deque(islice(iterator, n - 1), maxlen=n)
945
+ window = deque(islice(iterator, n - 1), maxlen=n)
951
946
for x in iterator:
952
947
window.append(x)
953
948
yield tuple(window)
@@ -981,7 +976,7 @@ and :term:`generators <generator>` which incur interpreter overhead.
981
976
"Return all contiguous non-empty subslices of a sequence."
982
977
# subslices('ABCD') → A AB ABC ABCD B BC BCD C CD D
983
978
slices = starmap(slice, combinations(range(len(seq) + 1), 2))
984
- return map(operator. getitem, repeat(seq), slices)
979
+ return map(getitem, repeat(seq), slices)
985
980
986
981
def iter_index(iterable, value, start=0, stop=None):
987
982
"Return indices where a value occurs in a sequence or iterable."
@@ -995,39 +990,40 @@ and :term:`generators <generator>` which incur interpreter overhead.
995
990
else:
996
991
stop = len(iterable) if stop is None else stop
997
992
i = start
998
- with contextlib. suppress(ValueError):
993
+ with suppress(ValueError):
999
994
while True:
1000
995
yield (i := seq_index(value, i, stop))
1001
996
i += 1
1002
997
1003
- def iter_except(func , exception, first=None):
998
+ def iter_except(function , exception, first=None):
1004
999
"Convert a call-until-exception interface to an iterator interface."
1005
1000
# iter_except(d.popitem, KeyError) → non-blocking dictionary iterator
1006
- with contextlib. suppress(exception):
1001
+ with suppress(exception):
1007
1002
if first is not None:
1008
1003
yield first()
1009
1004
while True:
1010
- yield func ()
1005
+ yield function ()
1011
1006
1012
1007
1013
1008
The following recipes have a more mathematical flavor:
1014
1009
1015
1010
.. testcode ::
1016
1011
1017
1012
def powerset(iterable):
1018
- "powerset([1,2,3]) → () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
1013
+ "Subsequences of the iterable from shortest to longest."
1014
+ # powerset([1,2,3]) → () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)
1019
1015
s = list(iterable)
1020
1016
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
1021
1017
1022
1018
def sum_of_squares(iterable):
1023
1019
"Add up the squares of the input values."
1024
1020
# sum_of_squares([10, 20, 30]) → 1400
1025
- return math. sumprod(*tee(iterable))
1021
+ return sumprod(*tee(iterable))
1026
1022
1027
- def reshape(matrix, cols ):
1023
+ def reshape(matrix, columns ):
1028
1024
"Reshape a 2-D matrix to have a given number of columns."
1029
1025
# reshape([(0, 1), (2, 3), (4, 5)], 3) → (0, 1, 2), (3, 4, 5)
1030
- return batched(chain.from_iterable(matrix), cols , strict=True)
1026
+ return batched(chain.from_iterable(matrix), columns , strict=True)
1031
1027
1032
1028
def transpose(matrix):
1033
1029
"Swap the rows and columns of a 2-D matrix."
@@ -1038,7 +1034,7 @@ The following recipes have a more mathematical flavor:
1038
1034
"Multiply two matrices."
1039
1035
# matmul([(7, 5), (3, 5)], [(2, 5), (7, 9)]) → (49, 80), (41, 60)
1040
1036
n = len(m2[0])
1041
- return batched(starmap(math. sumprod, product(m1, transpose(m2))), n)
1037
+ return batched(starmap(sumprod, product(m1, transpose(m2))), n)
1042
1038
1043
1039
def convolve(signal, kernel):
1044
1040
"""Discrete linear convolution of two iterables.
@@ -1059,16 +1055,16 @@ The following recipes have a more mathematical flavor:
1059
1055
n = len(kernel)
1060
1056
padded_signal = chain(repeat(0, n-1), signal, repeat(0, n-1))
1061
1057
windowed_signal = sliding_window(padded_signal, n)
1062
- return map(math. sumprod, repeat(kernel), windowed_signal)
1058
+ return map(sumprod, repeat(kernel), windowed_signal)
1063
1059
1064
1060
def polynomial_from_roots(roots):
1065
1061
"""Compute a polynomial's coefficients from its roots.
1066
1062
1067
1063
(x - 5) (x + 4) (x - 3) expands to: x³ -4x² -17x + 60
1068
1064
"""
1069
1065
# polynomial_from_roots([5, -4, 3]) → [1, -4, -17, 60]
1070
- factors = zip(repeat(1), map(operator. neg, roots))
1071
- return list(functools. reduce(convolve, factors, [1]))
1066
+ factors = zip(repeat(1), map(neg, roots))
1067
+ return list(reduce(convolve, factors, [1]))
1072
1068
1073
1069
def polynomial_eval(coefficients, x):
1074
1070
"""Evaluate a polynomial at a specific value.
@@ -1081,7 +1077,7 @@ The following recipes have a more mathematical flavor:
1081
1077
if not n:
1082
1078
return type(x)(0)
1083
1079
powers = map(pow, repeat(x), reversed(range(n)))
1084
- return math. sumprod(coefficients, powers)
1080
+ return sumprod(coefficients, powers)
1085
1081
1086
1082
def polynomial_derivative(coefficients):
1087
1083
"""Compute the first derivative of a polynomial.
@@ -1092,29 +1088,24 @@ The following recipes have a more mathematical flavor:
1092
1088
# polynomial_derivative([1, -4, -17, 60]) → [3, -8, -17]
1093
1089
n = len(coefficients)
1094
1090
powers = reversed(range(1, n))
1095
- return list(map(operator. mul, coefficients, powers))
1091
+ return list(map(mul, coefficients, powers))
1096
1092
1097
1093
def sieve(n):
1098
1094
"Primes less than n."
1099
1095
# sieve(30) → 2 3 5 7 11 13 17 19 23 29
1100
1096
if n > 2:
1101
1097
yield 2
1102
1098
data = bytearray((0, 1)) * (n // 2)
1103
- for p in iter_index(data, 1, start=3, stop=math. isqrt(n) + 1):
1099
+ for p in iter_index(data, 1, start=3, stop=isqrt(n) + 1):
1104
1100
data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p)))
1105
1101
yield from iter_index(data, 1, start=3)
1106
1102
1107
- def is_prime(n):
1108
- "Return True if n is prime."
1109
- # is_prime(1_000_000_000_000_403) → True
1110
- return n > 1 and all(n % p for p in sieve(math.isqrt(n) + 1))
1111
-
1112
1103
def factor(n):
1113
1104
"Prime factors of n."
1114
1105
# factor(99) → 3 3 11
1115
1106
# factor(1_000_000_000_000_007) → 47 59 360620266859
1116
1107
# factor(1_000_000_000_000_403) → 1000000000000403
1117
- for prime in sieve(math. isqrt(n) + 1):
1108
+ for prime in sieve(isqrt(n) + 1):
1118
1109
while not n % prime:
1119
1110
yield prime
1120
1111
n //= prime
@@ -1123,6 +1114,11 @@ The following recipes have a more mathematical flavor:
1123
1114
if n > 1:
1124
1115
yield n
1125
1116
1117
+ def is_prime(n):
1118
+ "Return True if n is prime."
1119
+ # is_prime(1_000_000_000_000_403) → True
1120
+ return n > 1 and next(factor(n)) == n
1121
+
1126
1122
def totient(n):
1127
1123
"Count of natural numbers up to n that are coprime to n."
1128
1124
# https://mathworld.wolfram.com/TotientFunction.html
@@ -1740,7 +1736,7 @@ The following recipes have a more mathematical flavor:
1740
1736
1741
1737
# Old recipes and their tests which are guaranteed to continue to work.
1742
1738
1743
- def sumprod (vec1, vec2):
1739
+ def old_sumprod_recipe (vec1, vec2):
1744
1740
"Compute a sum of products."
1745
1741
return sum(starmap(operator.mul, zip(vec1, vec2, strict=True)))
1746
1742
@@ -1823,7 +1819,7 @@ The following recipes have a more mathematical flavor:
1823
1819
32
1824
1820
1825
1821
1826
- >>> sumprod ([1 ,2 ,3 ], [4 ,5 ,6 ])
1822
+ >>> old_sumprod_recipe ([1 ,2 ,3 ], [4 ,5 ,6 ])
1827
1823
32
1828
1824
1829
1825
0 commit comments