diff options
-rw-r--r-- | Doc/library/itertools.rst | 74 |
1 files changed, 35 insertions, 39 deletions
diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 3b90d78..d1fb952 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -30,11 +30,6 @@ For instance, SML provides a tabulation tool: ``tabulate(f)`` which produces a sequence ``f(0), f(1), ...``. The same effect can be achieved in Python by combining :func:`map` and :func:`count` to form ``map(f, count())``. -These tools and their built-in counterparts also work well with the high-speed -functions in the :mod:`operator` module. For example, the multiplication -operator can be mapped across two vectors to form an efficient dot-product: -``sum(starmap(operator.mul, zip(vec1, vec2, strict=True)))``. - **Infinite iterators:** @@ -843,12 +838,11 @@ and :term:`generators <generator>` which incur interpreter overhead. .. testcode:: - import collections - import contextlib - import functools - import math - import operator - import random + from collections import deque + from contextlib import suppress + from functools import reduce + from math import sumprod, isqrt + from operator import itemgetter, getitem, mul, neg def take(n, iterable): "Return first n items of the iterable as a list." @@ -863,11 +857,11 @@ and :term:`generators <generator>` which incur interpreter overhead. "Return function(0), function(1), ..." return map(function, count(start)) - def repeatfunc(func, times=None, *args): - "Repeat calls to func with specified arguments." + def repeatfunc(function, times=None, *args): + "Repeat calls to a function with specified arguments." if times is None: - return starmap(func, repeat(args)) - return starmap(func, repeat(args, times)) + return starmap(function, repeat(args)) + return starmap(function, repeat(args, times)) def flatten(list_of_lists): "Flatten one level of nesting." @@ -885,13 +879,13 @@ and :term:`generators <generator>` which incur interpreter overhead. def tail(n, iterable): "Return an iterator over the last n items." # tail(3, 'ABCDEFG') → E F G - return iter(collections.deque(iterable, maxlen=n)) + return iter(deque(iterable, maxlen=n)) def consume(iterator, n=None): "Advance the iterator n-steps ahead. If n is None, consume entirely." # Use functions that consume iterators at C speed. if n is None: - collections.deque(iterator, maxlen=0) + deque(iterator, maxlen=0) else: next(islice(iterator, n, n), None) @@ -919,8 +913,8 @@ and :term:`generators <generator>` which incur interpreter overhead. # unique_justseen('AAAABBBCCDAABBB') → A B C D A B # unique_justseen('ABBcCAD', str.casefold) → A B c A D if key is None: - return map(operator.itemgetter(0), groupby(iterable)) - return map(next, map(operator.itemgetter(1), groupby(iterable, key))) + return map(itemgetter(0), groupby(iterable)) + return map(next, map(itemgetter(1), groupby(iterable, key))) def unique_everseen(iterable, key=None): "Yield unique elements, preserving order. Remember all elements ever seen." @@ -941,13 +935,14 @@ and :term:`generators <generator>` which incur interpreter overhead. 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, reverse=reverse), key=key) + sequenced = sorted(iterable, key=key, reverse=reverse) + return unique_justseen(sequenced, key=key) def sliding_window(iterable, n): "Collect data into overlapping fixed-length chunks or blocks." # sliding_window('ABCDEFG', 4) → ABCD BCDE CDEF DEFG iterator = iter(iterable) - window = collections.deque(islice(iterator, n - 1), maxlen=n) + window = deque(islice(iterator, n - 1), maxlen=n) for x in iterator: window.append(x) yield tuple(window) @@ -981,7 +976,7 @@ and :term:`generators <generator>` which incur interpreter overhead. "Return all contiguous non-empty subslices of a sequence." # subslices('ABCD') → A AB ABC ABCD B BC BCD C CD D slices = starmap(slice, combinations(range(len(seq) + 1), 2)) - return map(operator.getitem, repeat(seq), slices) + return map(getitem, repeat(seq), slices) def iter_index(iterable, value, start=0, stop=None): "Return indices where a value occurs in a sequence or iterable." @@ -995,19 +990,19 @@ and :term:`generators <generator>` which incur interpreter overhead. else: stop = len(iterable) if stop is None else stop i = start - with contextlib.suppress(ValueError): + with suppress(ValueError): while True: yield (i := seq_index(value, i, stop)) i += 1 - def iter_except(func, exception, first=None): + def iter_except(function, exception, first=None): "Convert a call-until-exception interface to an iterator interface." # iter_except(d.popitem, KeyError) → non-blocking dictionary iterator - with contextlib.suppress(exception): + with suppress(exception): if first is not None: yield first() while True: - yield func() + yield function() The following recipes have a more mathematical flavor: @@ -1015,6 +1010,7 @@ The following recipes have a more mathematical flavor: .. testcode:: def powerset(iterable): + "Subsequences of the iterable from shortest to longest." # powerset([1,2,3]) → () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3) s = list(iterable) return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) @@ -1022,12 +1018,12 @@ The following recipes have a more mathematical flavor: def sum_of_squares(iterable): "Add up the squares of the input values." # sum_of_squares([10, 20, 30]) → 1400 - return math.sumprod(*tee(iterable)) + return sumprod(*tee(iterable)) - def reshape(matrix, cols): + def reshape(matrix, columns): "Reshape a 2-D matrix to have a given number of columns." # reshape([(0, 1), (2, 3), (4, 5)], 3) → (0, 1, 2), (3, 4, 5) - return batched(chain.from_iterable(matrix), cols, strict=True) + return batched(chain.from_iterable(matrix), columns, strict=True) def transpose(matrix): "Swap the rows and columns of a 2-D matrix." @@ -1038,7 +1034,7 @@ The following recipes have a more mathematical flavor: "Multiply two matrices." # matmul([(7, 5), (3, 5)], [(2, 5), (7, 9)]) → (49, 80), (41, 60) n = len(m2[0]) - return batched(starmap(math.sumprod, product(m1, transpose(m2))), n) + return batched(starmap(sumprod, product(m1, transpose(m2))), n) def convolve(signal, kernel): """Discrete linear convolution of two iterables. @@ -1059,7 +1055,7 @@ The following recipes have a more mathematical flavor: n = len(kernel) padded_signal = chain(repeat(0, n-1), signal, repeat(0, n-1)) windowed_signal = sliding_window(padded_signal, n) - return map(math.sumprod, repeat(kernel), windowed_signal) + return map(sumprod, repeat(kernel), windowed_signal) def polynomial_from_roots(roots): """Compute a polynomial's coefficients from its roots. @@ -1067,8 +1063,8 @@ The following recipes have a more mathematical flavor: (x - 5) (x + 4) (x - 3) expands to: x³ -4x² -17x + 60 """ # polynomial_from_roots([5, -4, 3]) → [1, -4, -17, 60] - factors = zip(repeat(1), map(operator.neg, roots)) - return list(functools.reduce(convolve, factors, [1])) + factors = zip(repeat(1), map(neg, roots)) + return list(reduce(convolve, factors, [1])) def polynomial_eval(coefficients, x): """Evaluate a polynomial at a specific value. @@ -1081,7 +1077,7 @@ The following recipes have a more mathematical flavor: if not n: return type(x)(0) powers = map(pow, repeat(x), reversed(range(n))) - return math.sumprod(coefficients, powers) + return sumprod(coefficients, powers) def polynomial_derivative(coefficients): """Compute the first derivative of a polynomial. @@ -1092,7 +1088,7 @@ The following recipes have a more mathematical flavor: # polynomial_derivative([1, -4, -17, 60]) → [3, -8, -17] n = len(coefficients) powers = reversed(range(1, n)) - return list(map(operator.mul, coefficients, powers)) + return list(map(mul, coefficients, powers)) def sieve(n): "Primes less than n." @@ -1100,7 +1096,7 @@ The following recipes have a more mathematical flavor: if n > 2: yield 2 data = bytearray((0, 1)) * (n // 2) - for p in iter_index(data, 1, start=3, stop=math.isqrt(n) + 1): + for p in iter_index(data, 1, start=3, stop=isqrt(n) + 1): data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p))) yield from iter_index(data, 1, start=3) @@ -1109,7 +1105,7 @@ The following recipes have a more mathematical flavor: # factor(99) → 3 3 11 # factor(1_000_000_000_000_007) → 47 59 360620266859 # factor(1_000_000_000_000_403) → 1000000000000403 - for prime in sieve(math.isqrt(n) + 1): + for prime in sieve(isqrt(n) + 1): while not n % prime: yield prime n //= prime @@ -1740,7 +1736,7 @@ The following recipes have a more mathematical flavor: # Old recipes and their tests which are guaranteed to continue to work. - def sumprod(vec1, vec2): + def old_sumprod_recipe(vec1, vec2): "Compute a sum of products." return sum(starmap(operator.mul, zip(vec1, vec2, strict=True))) @@ -1823,7 +1819,7 @@ The following recipes have a more mathematical flavor: 32 - >>> sumprod([1,2,3], [4,5,6]) + >>> old_sumprod_recipe([1,2,3], [4,5,6]) 32 |