Skip to content

Commit 91be41a

Browse files
authored
bpo-44571: Add itertool recipe for a variant of takewhile() (GH-28167)
1 parent 65c5756 commit 91be41a

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

Doc/library/itertools.rst

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,34 @@ which incur interpreter overhead.
837837
t1, t2 = tee(iterable)
838838
return filterfalse(pred, t1), filter(pred, t2)
839839

840+
def before_and_after(predicate, it):
841+
""" Variant of takewhile() that allows complete
842+
access to the remainder of the iterator.
843+
844+
>>> all_upper, remainder = before_and_after(str.isupper, 'ABCdEfGhI')
845+
>>> str.join('', all_upper)
846+
'ABC'
847+
>>> str.join('', remainder)
848+
'dEfGhI'
849+
850+
Note that the first iterator must be fully
851+
consumed before the second iterator can
852+
generate valid results.
853+
"""
854+
it = iter(it)
855+
transition = []
856+
def true_iterator():
857+
for elem in it:
858+
if predicate(elem):
859+
yield elem
860+
else:
861+
transition.append(elem)
862+
return
863+
def remainder_iterator():
864+
yield from transition
865+
yield from it
866+
return true_iterator(), remainder_iterator()
867+
840868
def powerset(iterable):
841869
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
842870
s = list(iterable)
@@ -948,4 +976,3 @@ which incur interpreter overhead.
948976
c, n = c*(n-r)//n, n-1
949977
result.append(pool[-1-n])
950978
return tuple(result)
951-

Lib/test/test_itertools.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2412,6 +2412,40 @@ def test_permutations_sizeof(self):
24122412
... pending -= 1
24132413
... nexts = cycle(islice(nexts, pending))
24142414
2415+
>>> def partition(pred, iterable):
2416+
... "Use a predicate to partition entries into false entries and true entries"
2417+
... # partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9
2418+
... t1, t2 = tee(iterable)
2419+
... return filterfalse(pred, t1), filter(pred, t2)
2420+
2421+
>>> def before_and_after(predicate, it):
2422+
... ''' Variant of takewhile() that allows complete
2423+
... access to the remainder of the iterator.
2424+
...
2425+
... >>> all_upper, remainder = before_and_after(str.isupper, 'ABCdEfGhI')
2426+
... >>> str.join('', all_upper)
2427+
... 'ABC'
2428+
... >>> str.join('', remainder)
2429+
... 'dEfGhI'
2430+
...
2431+
... Note that the first iterator must be fully
2432+
... consumed before the second iterator can
2433+
... generate valid results.
2434+
... '''
2435+
... it = iter(it)
2436+
... transition = []
2437+
... def true_iterator():
2438+
... for elem in it:
2439+
... if predicate(elem):
2440+
... yield elem
2441+
... else:
2442+
... transition.append(elem)
2443+
... return
2444+
... def remainder_iterator():
2445+
... yield from transition
2446+
... yield from it
2447+
... return true_iterator(), remainder_iterator()
2448+
24152449
>>> def powerset(iterable):
24162450
... "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
24172451
... s = list(iterable)
@@ -2539,6 +2573,21 @@ def test_permutations_sizeof(self):
25392573
>>> list(roundrobin('abc', 'd', 'ef'))
25402574
['a', 'd', 'e', 'b', 'f', 'c']
25412575
2576+
>>> def is_odd(x):
2577+
... return x % 2 == 1
2578+
2579+
>>> evens, odds = partition(is_odd, range(10))
2580+
>>> list(evens)
2581+
[0, 2, 4, 6, 8]
2582+
>>> list(odds)
2583+
[1, 3, 5, 7, 9]
2584+
2585+
>>> all_upper, remainder = before_and_after(str.isupper, 'ABCdEfGhI')
2586+
>>> str.join('', all_upper)
2587+
'ABC'
2588+
>>> str.join('', remainder)
2589+
'dEfGhI'
2590+
25422591
>>> list(powerset([1,2,3]))
25432592
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
25442593

0 commit comments

Comments
 (0)