@@ -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
@@ -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):
1013
+ "Subsequences of the iterable from shortest to longest."
1018
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,15 +1088,15 @@ 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
@@ -1109,7 +1105,7 @@ The following recipes have a more mathematical flavor:
1109
1105
# factor(99) → 3 3 11
1110
1106
# factor(1_000_000_000_000_007) → 47 59 360620266859
1111
1107
# factor(1_000_000_000_000_403) → 1000000000000403
1112
- for prime in sieve(math. isqrt(n) + 1):
1108
+ for prime in sieve(isqrt(n) + 1):
1113
1109
while not n % prime:
1114
1110
yield prime
1115
1111
n //= prime
@@ -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