mirror of https://github.com/python/cpython
Misc improvements to the itertools docs (gh-125147)
This commit is contained in:
parent
760b1e103a
commit
b2a7272408
|
@ -134,7 +134,7 @@ loops that truncate the stream.
|
|||
To compute a running minimum, set *function* to :func:`min`.
|
||||
For a running maximum, set *function* to :func:`max`.
|
||||
Or for a running product, set *function* to :func:`operator.mul`.
|
||||
To build an `Amortization table
|
||||
To build an `amortization table
|
||||
<https://www.ramseysolutions.com/real-estate/amortization-schedule>`_,
|
||||
accumulate the interest and apply payments:
|
||||
|
||||
|
@ -736,6 +736,26 @@ loops that truncate the stream.
|
|||
allows nested :func:`tee` calls to share the same underlying data
|
||||
chain and to have a single update step rather than a chain of calls.
|
||||
|
||||
The flattening property makes tee iterators efficiently peekable:
|
||||
|
||||
.. testcode::
|
||||
|
||||
def lookahead(tee_iterator):
|
||||
"Return the next value without moving the input forward"
|
||||
[forked_iterator] = tee(tee_iterator, 1)
|
||||
return next(forked_iterator)
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> iterator = iter('abcdef')
|
||||
>>> [iterator] = tee(iterator, 1) # Make the input peekable
|
||||
>>> next(iterator) # Move the iterator forward
|
||||
'a'
|
||||
>>> lookahead(iterator) # Check next value
|
||||
'b'
|
||||
>>> next(iterator) # Continue moving forward
|
||||
'b'
|
||||
|
||||
``tee`` iterators are not threadsafe. A :exc:`RuntimeError` may be
|
||||
raised when simultaneously using iterators returned by the same :func:`tee`
|
||||
call, even if the original *iterable* is threadsafe.
|
||||
|
@ -952,15 +972,6 @@ and :term:`generators <generator>` which incur interpreter overhead.
|
|||
iterators = cycle(islice(iterators, num_active))
|
||||
yield from map(next, iterators)
|
||||
|
||||
def partition(predicate, iterable):
|
||||
"""Partition entries into false entries and true entries.
|
||||
|
||||
If *predicate* is slow, consider wrapping it with functools.lru_cache().
|
||||
"""
|
||||
# partition(is_odd, range(10)) → 0 2 4 6 8 and 1 3 5 7 9
|
||||
t1, t2 = tee(iterable)
|
||||
return filterfalse(predicate, t1), filter(predicate, t2)
|
||||
|
||||
def subslices(seq):
|
||||
"Return all contiguous non-empty subslices of a sequence."
|
||||
# subslices('ABCD') → A AB ABC ABCD B BC BCD C CD D
|
||||
|
@ -1178,15 +1189,19 @@ The following recipes have a more mathematical flavor:
|
|||
>>> list(it)
|
||||
['d', 'e', 'f']
|
||||
|
||||
|
||||
>>> list(prepend(1, [2, 3, 4]))
|
||||
[1, 2, 3, 4]
|
||||
|
||||
|
||||
>>> list(enumerate('abc'))
|
||||
[(0, 'a'), (1, 'b'), (2, 'c')]
|
||||
|
||||
|
||||
>>> list(islice(tabulate(lambda x: 2*x), 4))
|
||||
[0, 2, 4, 6]
|
||||
|
||||
|
||||
>>> list(tail(3, 'ABCDEFG'))
|
||||
['E', 'F', 'G']
|
||||
>>> # Verify the input is consumed greedily
|
||||
|
@ -1195,6 +1210,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> list(input_iterator)
|
||||
[]
|
||||
|
||||
|
||||
>>> it = iter(range(10))
|
||||
>>> consume(it, 3)
|
||||
>>> # Verify the input is consumed lazily
|
||||
|
@ -1205,6 +1221,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> next(it, 'Done')
|
||||
'Done'
|
||||
|
||||
|
||||
>>> nth('abcde', 3)
|
||||
'd'
|
||||
>>> nth('abcde', 9) is None
|
||||
|
@ -1216,6 +1233,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> list(it)
|
||||
['d', 'e']
|
||||
|
||||
|
||||
>>> [all_equal(s) for s in ('', 'A', 'AAAA', 'AAAB', 'AAABA')]
|
||||
[True, True, True, False, False]
|
||||
>>> [all_equal(s, key=str.casefold) for s in ('', 'A', 'AaAa', 'AAAB', 'AAABA')]
|
||||
|
@ -1229,24 +1247,19 @@ The following recipes have a more mathematical flavor:
|
|||
>>> ''.join(it)
|
||||
'bbccc'
|
||||
|
||||
|
||||
>>> quantify(range(99), lambda x: x%2==0)
|
||||
50
|
||||
|
||||
>>> quantify([True, False, False, True, True])
|
||||
3
|
||||
|
||||
>>> quantify(range(12), predicate=lambda x: x%2==1)
|
||||
6
|
||||
|
||||
|
||||
>>> a = [[1, 2, 3], [4, 5, 6]]
|
||||
>>> list(flatten(a))
|
||||
[1, 2, 3, 4, 5, 6]
|
||||
|
||||
>>> list(repeatfunc(pow, 5, 2, 3))
|
||||
[8, 8, 8, 8, 8]
|
||||
|
||||
>>> take(5, map(int, repeatfunc(random.random)))
|
||||
[0, 0, 0, 0, 0]
|
||||
|
||||
>>> list(ncycles('abc', 3))
|
||||
['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']
|
||||
|
@ -1256,9 +1269,11 @@ The following recipes have a more mathematical flavor:
|
|||
>>> list(input_iterator)
|
||||
[]
|
||||
|
||||
|
||||
>>> sum_of_squares([10, 20, 30])
|
||||
1400
|
||||
|
||||
|
||||
>>> list(reshape([(0, 1), (2, 3), (4, 5)], 3))
|
||||
[(0, 1, 2), (3, 4, 5)]
|
||||
>>> M = [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]
|
||||
|
@ -1279,6 +1294,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> list(reshape(M, 12))
|
||||
[(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)]
|
||||
|
||||
|
||||
>>> list(transpose([(1, 2, 3), (11, 22, 33)]))
|
||||
[(1, 11), (2, 22), (3, 33)]
|
||||
>>> # Verify that the inputs are consumed lazily
|
||||
|
@ -1290,11 +1306,13 @@ The following recipes have a more mathematical flavor:
|
|||
>>> list(zip(input1, input2))
|
||||
[(2, 22), (3, 33)]
|
||||
|
||||
|
||||
>>> list(matmul([(7, 5), (3, 5)], [[2, 5], [7, 9]]))
|
||||
[(49, 80), (41, 60)]
|
||||
>>> list(matmul([[2, 5], [7, 9], [3, 4]], [[7, 11, 5, 4, 9], [3, 5, 2, 6, 3]]))
|
||||
[(29, 47, 20, 38, 33), (76, 122, 53, 82, 90), (33, 53, 23, 36, 39)]
|
||||
|
||||
|
||||
>>> list(convolve([1, -1, -20], [1, -3])) == [1, -4, -17, 60]
|
||||
True
|
||||
>>> data = [20, 40, 24, 32, 20, 28, 16]
|
||||
|
@ -1317,6 +1335,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> list(signal_iterator)
|
||||
[30, 40, 50]
|
||||
|
||||
|
||||
>>> from fractions import Fraction
|
||||
>>> from decimal import Decimal
|
||||
>>> polynomial_eval([1, -4, -17, 60], x=5)
|
||||
|
@ -1348,6 +1367,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> polynomial_eval([11, 2], 7) == 11 * 7 + 2
|
||||
True
|
||||
|
||||
|
||||
>>> polynomial_from_roots([5, -4, 3])
|
||||
[1, -4, -17, 60]
|
||||
>>> factored = lambda x: (x - 5) * (x + 4) * (x - 3)
|
||||
|
@ -1355,9 +1375,11 @@ The following recipes have a more mathematical flavor:
|
|||
>>> all(factored(x) == expanded(x) for x in range(-10, 11))
|
||||
True
|
||||
|
||||
|
||||
>>> polynomial_derivative([1, -4, -17, 60])
|
||||
[3, -8, -17]
|
||||
|
||||
|
||||
>>> list(iter_index('AABCADEAF', 'A'))
|
||||
[0, 1, 4, 7]
|
||||
>>> list(iter_index('AABCADEAF', 'B'))
|
||||
|
@ -1415,12 +1437,14 @@ The following recipes have a more mathematical flavor:
|
|||
>>> ''.join(input_iterator)
|
||||
'DEAF'
|
||||
|
||||
|
||||
>>> # Verify that the target value can be a sequence.
|
||||
>>> seq = [[10, 20], [30, 40], 30, 40, [30, 40], 50]
|
||||
>>> target = [30, 40]
|
||||
>>> list(iter_index(seq, target))
|
||||
[1, 4]
|
||||
|
||||
|
||||
>>> # Verify faithfulness to type specific index() method behaviors.
|
||||
>>> # For example, bytes and str perform continuous-subsequence searches
|
||||
>>> # that do not match the general behavior specified
|
||||
|
@ -1450,6 +1474,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> set(sieve(10_000)).isdisjoint(carmichael)
|
||||
True
|
||||
|
||||
|
||||
>>> list(factor(99)) # Code example 1
|
||||
[3, 3, 11]
|
||||
>>> list(factor(1_000_000_000_000_007)) # Code example 2
|
||||
|
@ -1495,6 +1520,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> all(list(factor(n)) == sorted(factor(n)) for n in range(2_000))
|
||||
True
|
||||
|
||||
|
||||
>>> totient(0) # https://www.wolframalpha.com/input?i=totient+0
|
||||
0
|
||||
>>> first_totients = [1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6,
|
||||
|
@ -1514,9 +1540,15 @@ The following recipes have a more mathematical flavor:
|
|||
>>> totient(6 ** 20) == 1 * 2**19 * 2 * 3**19 # repeated primes
|
||||
True
|
||||
|
||||
|
||||
>>> list(flatten([('a', 'b'), (), ('c', 'd', 'e'), ('f',), ('g', 'h', 'i')]))
|
||||
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
|
||||
|
||||
|
||||
>>> list(repeatfunc(pow, 5, 2, 3))
|
||||
[8, 8, 8, 8, 8]
|
||||
>>> take(5, map(int, repeatfunc(random.random)))
|
||||
[0, 0, 0, 0, 0]
|
||||
>>> random.seed(85753098575309)
|
||||
>>> list(repeatfunc(random.random, 3))
|
||||
[0.16370491282496968, 0.45889608687313455, 0.3747076837820118]
|
||||
|
@ -1525,9 +1557,11 @@ The following recipes have a more mathematical flavor:
|
|||
>>> list(repeatfunc(pow, 3, 2, 5))
|
||||
[32, 32, 32]
|
||||
|
||||
|
||||
>>> list(grouper('abcdefg', 3, fillvalue='x'))
|
||||
[('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'x', 'x')]
|
||||
|
||||
|
||||
>>> it = grouper('abcdefg', 3, incomplete='strict')
|
||||
>>> next(it)
|
||||
('a', 'b', 'c')
|
||||
|
@ -1541,6 +1575,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> list(grouper('abcdefg', n=3, incomplete='ignore'))
|
||||
[('a', 'b', 'c'), ('d', 'e', 'f')]
|
||||
|
||||
|
||||
>>> list(sliding_window('ABCDEFG', 1))
|
||||
[('A',), ('B',), ('C',), ('D',), ('E',), ('F',), ('G',)]
|
||||
>>> list(sliding_window('ABCDEFG', 2))
|
||||
|
@ -1570,6 +1605,7 @@ The following recipes have a more mathematical flavor:
|
|||
...
|
||||
'zero or negative n not supported'
|
||||
|
||||
|
||||
>>> list(roundrobin('abc', 'd', 'ef'))
|
||||
['a', 'd', 'e', 'b', 'f', 'c']
|
||||
>>> ranges = [range(5, 1000), range(4, 3000), range(0), range(3, 2000), range(2, 5000), range(1, 3500)]
|
||||
|
@ -1583,38 +1619,19 @@ The following recipes have a more mathematical flavor:
|
|||
>>> ''.join(chain(*input_iterators))
|
||||
'dijkopqr'
|
||||
|
||||
>>> def is_odd(x):
|
||||
... return x % 2 == 1
|
||||
|
||||
>>> evens, odds = partition(is_odd, range(10))
|
||||
>>> list(evens)
|
||||
[0, 2, 4, 6, 8]
|
||||
>>> list(odds)
|
||||
[1, 3, 5, 7, 9]
|
||||
>>> # Verify that the input is consumed lazily
|
||||
>>> input_iterator = iter(range(10))
|
||||
>>> evens, odds = partition(is_odd, input_iterator)
|
||||
>>> next(odds)
|
||||
1
|
||||
>>> next(odds)
|
||||
3
|
||||
>>> next(evens)
|
||||
0
|
||||
>>> list(input_iterator)
|
||||
[4, 5, 6, 7, 8, 9]
|
||||
|
||||
>>> list(subslices('ABCD'))
|
||||
['A', 'AB', 'ABC', 'ABCD', 'B', 'BC', 'BCD', 'C', 'CD', 'D']
|
||||
|
||||
|
||||
>>> list(powerset([1,2,3]))
|
||||
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
|
||||
|
||||
>>> all(len(list(powerset(range(n)))) == 2**n for n in range(18))
|
||||
True
|
||||
|
||||
>>> list(powerset('abcde')) == sorted(sorted(set(powerset('abcde'))), key=len)
|
||||
True
|
||||
|
||||
|
||||
>>> list(unique_everseen('AAAABBBCCDAABBB'))
|
||||
['A', 'B', 'C', 'D']
|
||||
>>> list(unique_everseen('ABBCcAD', str.casefold))
|
||||
|
@ -1629,6 +1646,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> ''.join(input_iterator)
|
||||
'AAABBBCCDAABBB'
|
||||
|
||||
|
||||
>>> list(unique_justseen('AAAABBBCCDAABBB'))
|
||||
['A', 'B', 'C', 'D', 'A', 'B']
|
||||
>>> list(unique_justseen('ABBCcAD', str.casefold))
|
||||
|
@ -1643,6 +1661,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> ''.join(input_iterator)
|
||||
'AAABBBCCDAABBB'
|
||||
|
||||
|
||||
>>> list(unique([[1, 2], [3, 4], [1, 2]]))
|
||||
[[1, 2], [3, 4]]
|
||||
>>> list(unique('ABBcCAD', str.casefold))
|
||||
|
@ -1650,6 +1669,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> list(unique('ABBcCAD', str.casefold, reverse=True))
|
||||
['D', 'c', 'B', 'A']
|
||||
|
||||
|
||||
>>> d = dict(a=1, b=2, c=3)
|
||||
>>> it = iter_except(d.popitem, KeyError)
|
||||
>>> d['d'] = 4
|
||||
|
@ -1667,6 +1687,7 @@ The following recipes have a more mathematical flavor:
|
|||
>>> next(it, 'empty')
|
||||
'empty'
|
||||
|
||||
|
||||
>>> first_true('ABC0DEF1', '9', str.isdigit)
|
||||
'0'
|
||||
>>> # Verify that inputs are consumed lazily
|
||||
|
@ -1747,21 +1768,36 @@ The following recipes have a more mathematical flavor:
|
|||
|
||||
return true_iterator(), chain(transition, it)
|
||||
|
||||
def partition(predicate, iterable):
|
||||
"""Partition entries into false entries and true entries.
|
||||
|
||||
If *predicate* is slow, consider wrapping it with functools.lru_cache().
|
||||
"""
|
||||
# partition(is_odd, range(10)) → 0 2 4 6 8 and 1 3 5 7 9
|
||||
t1, t2 = tee(iterable)
|
||||
return filterfalse(predicate, t1), filter(predicate, t2)
|
||||
|
||||
|
||||
|
||||
.. doctest::
|
||||
:hide:
|
||||
|
||||
>>> dotproduct([1,2,3], [4,5,6])
|
||||
32
|
||||
|
||||
|
||||
>>> sumprod([1,2,3], [4,5,6])
|
||||
32
|
||||
|
||||
|
||||
>>> list(islice(pad_none('abc'), 0, 6))
|
||||
['a', 'b', 'c', None, None, None]
|
||||
|
||||
|
||||
>>> list(triplewise('ABCDEFG'))
|
||||
[('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E'), ('D', 'E', 'F'), ('E', 'F', 'G')]
|
||||
|
||||
|
||||
>>> population = 'ABCDEFGH'
|
||||
>>> for r in range(len(population) + 1):
|
||||
... seq = list(combinations(population, r))
|
||||
|
@ -1769,16 +1805,38 @@ The following recipes have a more mathematical flavor:
|
|||
... assert nth_combination(population, r, i) == seq[i]
|
||||
... for i in range(-len(seq), 0):
|
||||
... assert nth_combination(population, r, i) == seq[i]
|
||||
|
||||
...
|
||||
>>> iterable = 'abcde'
|
||||
>>> r = 3
|
||||
>>> combos = list(combinations(iterable, r))
|
||||
>>> all(nth_combination(iterable, r, i) == comb for i, comb in enumerate(combos))
|
||||
True
|
||||
|
||||
|
||||
>>> it = iter('ABCdEfGhI')
|
||||
>>> all_upper, remainder = before_and_after(str.isupper, it)
|
||||
>>> ''.join(all_upper)
|
||||
'ABC'
|
||||
>>> ''.join(remainder)
|
||||
'dEfGhI'
|
||||
|
||||
|
||||
>>> def is_odd(x):
|
||||
... return x % 2 == 1
|
||||
...
|
||||
>>> evens, odds = partition(is_odd, range(10))
|
||||
>>> list(evens)
|
||||
[0, 2, 4, 6, 8]
|
||||
>>> list(odds)
|
||||
[1, 3, 5, 7, 9]
|
||||
>>> # Verify that the input is consumed lazily
|
||||
>>> input_iterator = iter(range(10))
|
||||
>>> evens, odds = partition(is_odd, input_iterator)
|
||||
>>> next(odds)
|
||||
1
|
||||
>>> next(odds)
|
||||
3
|
||||
>>> next(evens)
|
||||
0
|
||||
>>> list(input_iterator)
|
||||
[4, 5, 6, 7, 8, 9]
|
||||
|
|
Loading…
Reference in New Issue