@@ -795,11 +795,11 @@ which incur interpreter overhead.
795
795
import random
796
796
797
797
def take(n, iterable):
798
- "Return first n items of the iterable as a list"
798
+ "Return first n items of the iterable as a list. "
799
799
return list(islice(iterable, n))
800
800
801
801
def prepend(value, iterable):
802
- "Prepend a single value in front of an iterable"
802
+ "Prepend a single value in front of an iterable. "
803
803
# prepend(1, [2, 3, 4]) --> 1 2 3 4
804
804
return chain([value], iterable)
805
805
@@ -817,15 +817,15 @@ which incur interpreter overhead.
817
817
return starmap(func, repeat(args, times))
818
818
819
819
def flatten(list_of_lists):
820
- "Flatten one level of nesting"
820
+ "Flatten one level of nesting. "
821
821
return chain.from_iterable(list_of_lists)
822
822
823
823
def ncycles(iterable, n):
824
- "Returns the sequence elements n times"
824
+ "Returns the sequence elements n times. "
825
825
return chain.from_iterable(repeat(tuple(iterable), n))
826
826
827
827
def tail(n, iterable):
828
- "Return an iterator over the last n items"
828
+ "Return an iterator over the last n items. "
829
829
# tail(3, 'ABCDEFG') --> E F G
830
830
return iter(collections.deque(iterable, maxlen=n))
831
831
@@ -840,15 +840,15 @@ which incur interpreter overhead.
840
840
next(islice(iterator, n, n), None)
841
841
842
842
def nth(iterable, n, default=None):
843
- "Returns the nth item or a default value"
843
+ "Returns the nth item or a default value. "
844
844
return next(islice(iterable, n, None), default)
845
845
846
846
def quantify(iterable, pred=bool):
847
847
"Given a predicate that returns True or False, count the True results."
848
848
return sum(map(pred, iterable))
849
849
850
850
def all_equal(iterable):
851
- "Returns True if all the elements are equal to each other"
851
+ "Returns True if all the elements are equal to each other. "
852
852
g = groupby(iterable)
853
853
return next(g, True) and not next(g, False)
854
854
@@ -865,6 +865,30 @@ which incur interpreter overhead.
865
865
# first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
866
866
return next(filter(pred, iterable), default)
867
867
868
+ def unique_everseen(iterable, key=None):
869
+ "List unique elements, preserving order. Remember all elements ever seen."
870
+ # unique_everseen('AAAABBBCCDAABBB') --> A B C D
871
+ # unique_everseen('ABBcCAD', str.casefold) --> A B c D
872
+ seen = set()
873
+ if key is None:
874
+ for element in filterfalse(seen.__contains__, iterable):
875
+ seen.add(element)
876
+ yield element
877
+ else:
878
+ for element in iterable:
879
+ k = key(element)
880
+ if k not in seen:
881
+ seen.add(k)
882
+ yield element
883
+
884
+ def unique_justseen(iterable, key=None):
885
+ "List unique elements, preserving order. Remember only the element just seen."
886
+ # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
887
+ # unique_justseen('ABBcCAD', str.casefold) --> A B c A D
888
+ if key is None:
889
+ return map(operator.itemgetter(0), groupby(iterable))
890
+ return map(next, map(operator.itemgetter(1), groupby(iterable, key)))
891
+
868
892
def iter_index(iterable, value, start=0, stop=None):
869
893
"Return indices where a value occurs in a sequence or iterable."
870
894
# iter_index('AABCADEAF', 'A') --> 0 1 4 7
@@ -885,31 +909,17 @@ which incur interpreter overhead.
885
909
except ValueError:
886
910
pass
887
911
888
- def iter_except(func, exception, first=None):
889
- """ Call a function repeatedly until an exception is raised.
890
-
891
- Converts a call-until-exception interface to an iterator interface.
892
- Like builtins.iter(func, sentinel) but uses an exception instead
893
- of a sentinel to end the loop.
894
-
895
- Examples:
896
- iter_except(functools.partial(heappop, h), IndexError) # priority queue iterator
897
- iter_except(d.popitem, KeyError) # non-blocking dict iterator
898
- iter_except(d.popleft, IndexError) # non-blocking deque iterator
899
- iter_except(q.get_nowait, Queue.Empty) # loop over a producer Queue
900
- iter_except(s.pop, KeyError) # non-blocking set iterator
901
-
902
- """
903
- try:
904
- if first is not None:
905
- yield first() # For database APIs needing an initial cast to db.first()
906
- while True:
907
- yield func()
908
- except exception:
909
- pass
912
+ def sliding_window(iterable, n):
913
+ "Collect data into overlapping fixed-length chunks or blocks."
914
+ # sliding_window('ABCDEFG', 4) --> ABCD BCDE CDEF DEFG
915
+ it = iter(iterable)
916
+ window = collections.deque(islice(it, n-1), maxlen=n)
917
+ for x in it:
918
+ window.append(x)
919
+ yield tuple(window)
910
920
911
921
def grouper(iterable, n, *, incomplete='fill', fillvalue=None):
912
- "Collect data into non-overlapping fixed-length chunks or blocks"
922
+ "Collect data into non-overlapping fixed-length chunks or blocks. "
913
923
# grouper('ABCDEFG', 3, fillvalue='x') --> ABC DEF Gxx
914
924
# grouper('ABCDEFG', 3, incomplete='strict') --> ABC DEF ValueError
915
925
# grouper('ABCDEFG', 3, incomplete='ignore') --> ABC DEF
@@ -924,16 +934,9 @@ which incur interpreter overhead.
924
934
case _:
925
935
raise ValueError('Expected fill, strict, or ignore')
926
936
927
- def sliding_window(iterable, n):
928
- # sliding_window('ABCDEFG', 4) --> ABCD BCDE CDEF DEFG
929
- it = iter(iterable)
930
- window = collections.deque(islice(it, n-1), maxlen=n)
931
- for x in it:
932
- window.append(x)
933
- yield tuple(window)
934
-
935
937
def roundrobin(*iterables):
936
- "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
938
+ "Visit input iterables in a cycle until each is exhausted."
939
+ # roundrobin('ABC', 'D', 'EF') --> A D E B F C
937
940
# Recipe credited to George Sakkis
938
941
num_active = len(iterables)
939
942
nexts = cycle(iter(it).__next__ for it in iterables)
@@ -956,11 +959,43 @@ which incur interpreter overhead.
956
959
return filterfalse(pred, t1), filter(pred, t2)
957
960
958
961
def subslices(seq):
959
- "Return all contiguous non-empty subslices of a sequence"
962
+ "Return all contiguous non-empty subslices of a sequence. "
960
963
# subslices('ABCD') --> A AB ABC ABCD B BC BCD C CD D
961
964
slices = starmap(slice, combinations(range(len(seq) + 1), 2))
962
965
return map(operator.getitem, repeat(seq), slices)
963
966
967
+ def iter_except(func, exception, first=None):
968
+ """ Call a function repeatedly until an exception is raised.
969
+
970
+ Converts a call-until-exception interface to an iterator interface.
971
+ Like builtins.iter(func, sentinel) but uses an exception instead
972
+ of a sentinel to end the loop.
973
+
974
+ Priority queue iterator:
975
+ iter_except(functools.partial(heappop, h), IndexError)
976
+
977
+ Non-blocking dictionary iterator:
978
+ iter_except(d.popitem, KeyError)
979
+
980
+ Non-blocking deque iterator:
981
+ iter_except(d.popleft, IndexError)
982
+
983
+ Non-blocking iterator over a producer Queue:
984
+ iter_except(q.get_nowait, Queue.Empty)
985
+
986
+ Non-blocking set iterator:
987
+ iter_except(s.pop, KeyError)
988
+
989
+ """
990
+ try:
991
+ if first is not None:
992
+ # For database APIs needing an initial call to db.first()
993
+ yield first()
994
+ while True:
995
+ yield func()
996
+ except exception:
997
+ pass
998
+
964
999
def before_and_after(predicate, it):
965
1000
""" Variant of takewhile() that allows complete
966
1001
access to the remainder of the iterator.
@@ -972,54 +1007,21 @@ which incur interpreter overhead.
972
1007
>>> ' ' .join(remainder) # takewhile() would lose the 'd'
973
1008
'dEfGhI'
974
1009
975
- Note that the first iterator must be fully
976
- consumed before the second iterator can
977
- generate valid results.
1010
+ Note that the true iterator must be fully consumed
1011
+ before the remainder iterator can generate valid results.
978
1012
"""
979
1013
it = iter(it)
980
1014
transition = []
1015
+
981
1016
def true_iterator():
982
1017
for elem in it:
983
1018
if predicate(elem):
984
1019
yield elem
985
1020
else:
986
1021
transition.append(elem)
987
1022
return
988
- def remainder_iterator():
989
- yield from transition
990
- yield from it
991
- return true_iterator(), remainder_iterator()
992
1023
993
- def unique_everseen(iterable, key=None):
994
- "List unique elements, preserving order. Remember all elements ever seen."
995
- # unique_everseen('AAAABBBCCDAABBB') --> A B C D
996
- # unique_everseen('ABBcCAD', str.lower) --> A B c D
997
- seen = set()
998
- if key is None:
999
- for element in filterfalse(seen.__contains__, iterable):
1000
- seen.add(element)
1001
- yield element
1002
- # For order preserving deduplication,
1003
- # a faster but non-lazy solution is:
1004
- # yield from dict.fromkeys(iterable)
1005
- else:
1006
- for element in iterable:
1007
- k = key(element)
1008
- if k not in seen:
1009
- seen.add(k)
1010
- yield element
1011
- # For use cases that allow the last matching element to be returned,
1012
- # a faster but non-lazy solution is:
1013
- # t1, t2 = tee(iterable)
1014
- # yield from dict(zip(map(key, t1), t2)).values()
1015
-
1016
- def unique_justseen(iterable, key=None):
1017
- "List unique elements, preserving order. Remember only the element just seen."
1018
- # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
1019
- # unique_justseen('ABBcCAD', str.lower) --> A B c A D
1020
- if key is None:
1021
- return map(operator.itemgetter(0), groupby(iterable))
1022
- return map(next, map(operator.itemgetter(1), groupby(iterable, key)))
1024
+ return true_iterator(), chain(transition, it)
1023
1025
1024
1026
1025
1027
The following recipes have a more mathematical flavor:
@@ -1550,16 +1552,16 @@ The following recipes have a more mathematical flavor:
1550
1552
1551
1553
>>> list (unique_everseen(' AAAABBBCCDAABBB' ))
1552
1554
['A', 'B', 'C', 'D']
1553
- >>> list (unique_everseen(' ABBCcAD' , str .lower ))
1555
+ >>> list (unique_everseen(' ABBCcAD' , str .casefold ))
1554
1556
['A', 'B', 'C', 'D']
1555
- >>> list (unique_everseen(' ABBcCAD' , str .lower ))
1557
+ >>> list (unique_everseen(' ABBcCAD' , str .casefold ))
1556
1558
['A', 'B', 'c', 'D']
1557
1559
1558
1560
>>> list (unique_justseen(' AAAABBBCCDAABBB' ))
1559
1561
['A', 'B', 'C', 'D', 'A', 'B']
1560
- >>> list (unique_justseen(' ABBCcAD' , str .lower ))
1562
+ >>> list (unique_justseen(' ABBCcAD' , str .casefold ))
1561
1563
['A', 'B', 'C', 'A', 'D']
1562
- >>> list (unique_justseen(' ABBcCAD' , str .lower ))
1564
+ >>> list (unique_justseen(' ABBcCAD' , str .casefold ))
1563
1565
['A', 'B', 'c', 'A', 'D']
1564
1566
1565
1567
>>> d = dict (a = 1 , b = 2 , c = 3 )
0 commit comments