Skip to content

Commit

Permalink
[3.12] Misc itertool recipe improvements, mostly docstrings and comme…
Browse files Browse the repository at this point in the history
…nts (pythongh-109555) (python#109572)

(cherry picked from commit f2636d2)

Co-authored-by: Raymond Hettinger <[email protected]>
  • Loading branch information
miss-islington and rhettinger authored Sep 22, 2023
1 parent 9e4ac21 commit 0015a9a
Showing 1 changed file with 44 additions and 37 deletions.
81 changes: 44 additions & 37 deletions Doc/library/itertools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ which incur interpreter overhead.
return next(islice(iterable, n, None), default)

def quantify(iterable, pred=bool):
"Count how many times the predicate is True"
"Given a predicate that returns True or False, count the True results."
return sum(map(pred, iterable))

def all_equal(iterable):
Expand Down Expand Up @@ -1028,36 +1028,6 @@ The following recipes have a more mathematical flavor:
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

def sieve(n):
"Primes less than n."
# sieve(30) --> 2 3 5 7 11 13 17 19 23 29
if n > 2:
yield 2
start = 3
data = bytearray((0, 1)) * (n // 2)
limit = math.isqrt(n) + 1
for p in iter_index(data, 1, start, limit):
yield from iter_index(data, 1, start, p*p)
data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p)))
start = p*p
yield from iter_index(data, 1, start)

def factor(n):
"Prime factors of n."
# 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):
while True:
if n % prime:
break
yield prime
n //= prime
if n == 1:
return
if n > 1:
yield n

def sum_of_squares(it):
"Add up the squares of the input values."
# sum_of_squares([10, 20, 30]) -> 1400
Expand All @@ -1075,14 +1045,21 @@ The following recipes have a more mathematical flavor:
return batched(starmap(math.sumprod, product(m1, transpose(m2))), n)

def convolve(signal, kernel):
"""Linear convolution of two iterables.
"""Discrete linear convolution of two iterables.

The kernel is fully consumed before the calculations begin.
The signal is consumed lazily and can be infinite.

Convolutions are mathematically commutative.
If the signal and kernel are swapped,
the output will be the same.

Article: https://betterexplained.com/articles/intuitive-convolution/
Video: https://www.youtube.com/watch?v=KuXjwB4LzSA
"""
# convolve(data, [0.25, 0.25, 0.25, 0.25]) --> Moving average (blur)
# convolve(data, [1, -1]) --> 1st finite difference (1st derivative)
# convolve(data, [1, -2, 1]) --> 2nd finite difference (2nd derivative)
# convolve(data, [1/2, 0, -1/2]) --> 1st derivative estimate
# convolve(data, [1, -2, 1]) --> 2nd derivative estimate
kernel = tuple(kernel)[::-1]
n = len(kernel)
padded_signal = chain(repeat(0, n-1), signal, repeat(0, n-1))
Expand All @@ -1106,8 +1083,8 @@ The following recipes have a more mathematical flavor:
# Evaluate x³ -4x² -17x + 60 at x = 2.5
# polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125
n = len(coefficients)
if n == 0:
return x * 0 # coerce zero to the type of x
if not n:
return type(x)(0)
powers = map(pow, repeat(x), reversed(range(n)))
return math.sumprod(coefficients, powers)

Expand All @@ -1122,6 +1099,36 @@ The following recipes have a more mathematical flavor:
powers = reversed(range(1, n))
return list(map(operator.mul, coefficients, powers))

def sieve(n):
"Primes less than n."
# sieve(30) --> 2 3 5 7 11 13 17 19 23 29
if n > 2:
yield 2
start = 3
data = bytearray((0, 1)) * (n // 2)
limit = math.isqrt(n) + 1
for p in iter_index(data, 1, start, limit):
yield from iter_index(data, 1, start, p*p)
data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p)))
start = p*p
yield from iter_index(data, 1, start)

def factor(n):
"Prime factors of n."
# 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):
while True:
if n % prime:
break
yield prime
n //= prime
if n == 1:
return
if n > 1:
yield n

def nth_combination(iterable, r, index):
"Equivalent to list(combinations(iterable, r))[index]"
pool = tuple(iterable)
Expand Down Expand Up @@ -1297,7 +1304,7 @@ The following recipes have a more mathematical flavor:
>>> polynomial_eval([], Fraction(2, 3))
Fraction(0, 1)
>>> polynomial_eval([], Decimal('1.75'))
Decimal('0.00')
Decimal('0')
>>> polynomial_eval([11], 7) == 11
True
>>> polynomial_eval([11, 2], 7) == 11 * 7 + 2
Expand Down

0 comments on commit 0015a9a

Please sign in to comment.