Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b5dc0f8

Browse files
authored
Misc minor improvements to the itertools recipes (gh-113477)
1 parent 48c4973 commit b5dc0f8

File tree

1 file changed

+83
-81
lines changed

1 file changed

+83
-81
lines changed

Doc/library/itertools.rst

Lines changed: 83 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -803,11 +803,11 @@ which incur interpreter overhead.
803803
import random
804804

805805
def take(n, iterable):
806-
"Return first n items of the iterable as a list"
806+
"Return first n items of the iterable as a list."
807807
return list(islice(iterable, n))
808808

809809
def prepend(value, iterable):
810-
"Prepend a single value in front of an iterable"
810+
"Prepend a single value in front of an iterable."
811811
# prepend(1, [2, 3, 4]) --> 1 2 3 4
812812
return chain([value], iterable)
813813

@@ -825,15 +825,15 @@ which incur interpreter overhead.
825825
return starmap(func, repeat(args, times))
826826

827827
def flatten(list_of_lists):
828-
"Flatten one level of nesting"
828+
"Flatten one level of nesting."
829829
return chain.from_iterable(list_of_lists)
830830

831831
def ncycles(iterable, n):
832-
"Returns the sequence elements n times"
832+
"Returns the sequence elements n times."
833833
return chain.from_iterable(repeat(tuple(iterable), n))
834834

835835
def tail(n, iterable):
836-
"Return an iterator over the last n items"
836+
"Return an iterator over the last n items."
837837
# tail(3, 'ABCDEFG') --> E F G
838838
return iter(collections.deque(iterable, maxlen=n))
839839

@@ -848,15 +848,15 @@ which incur interpreter overhead.
848848
next(islice(iterator, n, n), None)
849849

850850
def nth(iterable, n, default=None):
851-
"Returns the nth item or a default value"
851+
"Returns the nth item or a default value."
852852
return next(islice(iterable, n, None), default)
853853

854854
def quantify(iterable, pred=bool):
855855
"Given a predicate that returns True or False, count the True results."
856856
return sum(map(pred, iterable))
857857

858858
def all_equal(iterable):
859-
"Returns True if all the elements are equal to each other"
859+
"Returns True if all the elements are equal to each other."
860860
g = groupby(iterable)
861861
return next(g, True) and not next(g, False)
862862

@@ -873,6 +873,30 @@ which incur interpreter overhead.
873873
# first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
874874
return next(filter(pred, iterable), default)
875875

876+
def unique_everseen(iterable, key=None):
877+
"List unique elements, preserving order. Remember all elements ever seen."
878+
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
879+
# unique_everseen('ABBcCAD', str.casefold) --> A B c D
880+
seen = set()
881+
if key is None:
882+
for element in filterfalse(seen.__contains__, iterable):
883+
seen.add(element)
884+
yield element
885+
else:
886+
for element in iterable:
887+
k = key(element)
888+
if k not in seen:
889+
seen.add(k)
890+
yield element
891+
892+
def unique_justseen(iterable, key=None):
893+
"List unique elements, preserving order. Remember only the element just seen."
894+
# unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
895+
# unique_justseen('ABBcCAD', str.casefold) --> A B c A D
896+
if key is None:
897+
return map(operator.itemgetter(0), groupby(iterable))
898+
return map(next, map(operator.itemgetter(1), groupby(iterable, key)))
899+
876900
def iter_index(iterable, value, start=0, stop=None):
877901
"Return indices where a value occurs in a sequence or iterable."
878902
# iter_index('AABCADEAF', 'A') --> 0 1 4 7
@@ -893,31 +917,17 @@ which incur interpreter overhead.
893917
except ValueError:
894918
pass
895919

896-
def iter_except(func, exception, first=None):
897-
""" Call a function repeatedly until an exception is raised.
898-
899-
Converts a call-until-exception interface to an iterator interface.
900-
Like builtins.iter(func, sentinel) but uses an exception instead
901-
of a sentinel to end the loop.
902-
903-
Examples:
904-
iter_except(functools.partial(heappop, h), IndexError) # priority queue iterator
905-
iter_except(d.popitem, KeyError) # non-blocking dict iterator
906-
iter_except(d.popleft, IndexError) # non-blocking deque iterator
907-
iter_except(q.get_nowait, Queue.Empty) # loop over a producer Queue
908-
iter_except(s.pop, KeyError) # non-blocking set iterator
909-
910-
"""
911-
try:
912-
if first is not None:
913-
yield first() # For database APIs needing an initial cast to db.first()
914-
while True:
915-
yield func()
916-
except exception:
917-
pass
920+
def sliding_window(iterable, n):
921+
"Collect data into overlapping fixed-length chunks or blocks."
922+
# sliding_window('ABCDEFG', 4) --> ABCD BCDE CDEF DEFG
923+
it = iter(iterable)
924+
window = collections.deque(islice(it, n-1), maxlen=n)
925+
for x in it:
926+
window.append(x)
927+
yield tuple(window)
918928

919929
def grouper(iterable, n, *, incomplete='fill', fillvalue=None):
920-
"Collect data into non-overlapping fixed-length chunks or blocks"
930+
"Collect data into non-overlapping fixed-length chunks or blocks."
921931
# grouper('ABCDEFG', 3, fillvalue='x') --> ABC DEF Gxx
922932
# grouper('ABCDEFG', 3, incomplete='strict') --> ABC DEF ValueError
923933
# grouper('ABCDEFG', 3, incomplete='ignore') --> ABC DEF
@@ -932,16 +942,9 @@ which incur interpreter overhead.
932942
case _:
933943
raise ValueError('Expected fill, strict, or ignore')
934944
935-
def sliding_window(iterable, n):
936-
# sliding_window('ABCDEFG', 4) --> ABCD BCDE CDEF DEFG
937-
it = iter(iterable)
938-
window = collections.deque(islice(it, n-1), maxlen=n)
939-
for x in it:
940-
window.append(x)
941-
yield tuple(window)
942-
943945
def roundrobin(*iterables):
944-
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
946+
"Visit input iterables in a cycle until each is exhausted."
947+
# roundrobin('ABC', 'D', 'EF') --> A D E B F C
945948
# Recipe credited to George Sakkis
946949
num_active = len(iterables)
947950
nexts = cycle(iter(it).__next__ for it in iterables)
@@ -964,11 +967,43 @@ which incur interpreter overhead.
964967
return filterfalse(pred, t1), filter(pred, t2)
965968

966969
def subslices(seq):
967-
"Return all contiguous non-empty subslices of a sequence"
970+
"Return all contiguous non-empty subslices of a sequence."
968971
# subslices('ABCD') --> A AB ABC ABCD B BC BCD C CD D
969972
slices = starmap(slice, combinations(range(len(seq) + 1), 2))
970973
return map(operator.getitem, repeat(seq), slices)
971974

975+
def iter_except(func, exception, first=None):
976+
""" Call a function repeatedly until an exception is raised.
977+
978+
Converts a call-until-exception interface to an iterator interface.
979+
Like builtins.iter(func, sentinel) but uses an exception instead
980+
of a sentinel to end the loop.
981+
982+
Priority queue iterator:
983+
iter_except(functools.partial(heappop, h), IndexError)
984+
985+
Non-blocking dictionary iterator:
986+
iter_except(d.popitem, KeyError)
987+
988+
Non-blocking deque iterator:
989+
iter_except(d.popleft, IndexError)
990+
991+
Non-blocking iterator over a producer Queue:
992+
iter_except(q.get_nowait, Queue.Empty)
993+
994+
Non-blocking set iterator:
995+
iter_except(s.pop, KeyError)
996+
997+
"""
998+
try:
999+
if first is not None:
1000+
# For database APIs needing an initial call to db.first()
1001+
yield first()
1002+
while True:
1003+
yield func()
1004+
except exception:
1005+
pass
1006+
9721007
def before_and_after(predicate, it):
9731008
""" Variant of takewhile() that allows complete
9741009
access to the remainder of the iterator.
@@ -980,54 +1015,21 @@ which incur interpreter overhead.
9801015
>>> ''.join(remainder) # takewhile() would lose the 'd'
9811016
'dEfGhI'
9821017

983-
Note that the first iterator must be fully
984-
consumed before the second iterator can
985-
generate valid results.
1018+
Note that the true iterator must be fully consumed
1019+
before the remainder iterator can generate valid results.
9861020
"""
9871021
it = iter(it)
9881022
transition = []
1023+
9891024
def true_iterator():
9901025
for elem in it:
9911026
if predicate(elem):
9921027
yield elem
9931028
else:
9941029
transition.append(elem)
9951030
return
996-
def remainder_iterator():
997-
yield from transition
998-
yield from it
999-
return true_iterator(), remainder_iterator()
10001031

1001-
def unique_everseen(iterable, key=None):
1002-
"List unique elements, preserving order. Remember all elements ever seen."
1003-
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
1004-
# unique_everseen('ABBcCAD', str.lower) --> A B c D
1005-
seen = set()
1006-
if key is None:
1007-
for element in filterfalse(seen.__contains__, iterable):
1008-
seen.add(element)
1009-
yield element
1010-
# For order preserving deduplication,
1011-
# a faster but non-lazy solution is:
1012-
# yield from dict.fromkeys(iterable)
1013-
else:
1014-
for element in iterable:
1015-
k = key(element)
1016-
if k not in seen:
1017-
seen.add(k)
1018-
yield element
1019-
# For use cases that allow the last matching element to be returned,
1020-
# a faster but non-lazy solution is:
1021-
# t1, t2 = tee(iterable)
1022-
# yield from dict(zip(map(key, t1), t2)).values()
1023-
1024-
def unique_justseen(iterable, key=None):
1025-
"List unique elements, preserving order. Remember only the element just seen."
1026-
# unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
1027-
# unique_justseen('ABBcCAD', str.lower) --> A B c A D
1028-
if key is None:
1029-
return map(operator.itemgetter(0), groupby(iterable))
1030-
return map(next, map(operator.itemgetter(1), groupby(iterable, key)))
1032+
return true_iterator(), chain(transition, it)
10311033

10321034

10331035
The following recipes have a more mathematical flavor:
@@ -1562,16 +1564,16 @@ The following recipes have a more mathematical flavor:
15621564

15631565
>>> list(unique_everseen('AAAABBBCCDAABBB'))
15641566
['A', 'B', 'C', 'D']
1565-
>>> list(unique_everseen('ABBCcAD', str.lower))
1567+
>>> list(unique_everseen('ABBCcAD', str.casefold))
15661568
['A', 'B', 'C', 'D']
1567-
>>> list(unique_everseen('ABBcCAD', str.lower))
1569+
>>> list(unique_everseen('ABBcCAD', str.casefold))
15681570
['A', 'B', 'c', 'D']
15691571

15701572
>>> list(unique_justseen('AAAABBBCCDAABBB'))
15711573
['A', 'B', 'C', 'D', 'A', 'B']
1572-
>>> list(unique_justseen('ABBCcAD', str.lower))
1574+
>>> list(unique_justseen('ABBCcAD', str.casefold))
15731575
['A', 'B', 'C', 'A', 'D']
1574-
>>> list(unique_justseen('ABBcCAD', str.lower))
1576+
>>> list(unique_justseen('ABBcCAD', str.casefold))
15751577
['A', 'B', 'c', 'A', 'D']
15761578

15771579
>>> d = dict(a=1, b=2, c=3)

0 commit comments

Comments
 (0)