@@ -803,11 +803,11 @@ which incur interpreter overhead.
803
803
import random
804
804
805
805
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. "
807
807
return list(islice(iterable, n))
808
808
809
809
def prepend(value, iterable):
810
- "Prepend a single value in front of an iterable"
810
+ "Prepend a single value in front of an iterable. "
811
811
# prepend(1, [2, 3, 4]) --> 1 2 3 4
812
812
return chain([value], iterable)
813
813
@@ -825,15 +825,15 @@ which incur interpreter overhead.
825
825
return starmap(func, repeat(args, times))
826
826
827
827
def flatten(list_of_lists):
828
- "Flatten one level of nesting"
828
+ "Flatten one level of nesting. "
829
829
return chain.from_iterable(list_of_lists)
830
830
831
831
def ncycles(iterable, n):
832
- "Returns the sequence elements n times"
832
+ "Returns the sequence elements n times. "
833
833
return chain.from_iterable(repeat(tuple(iterable), n))
834
834
835
835
def tail(n, iterable):
836
- "Return an iterator over the last n items"
836
+ "Return an iterator over the last n items. "
837
837
# tail(3, 'ABCDEFG') --> E F G
838
838
return iter(collections.deque(iterable, maxlen=n))
839
839
@@ -848,15 +848,15 @@ which incur interpreter overhead.
848
848
next(islice(iterator, n, n), None)
849
849
850
850
def nth(iterable, n, default=None):
851
- "Returns the nth item or a default value"
851
+ "Returns the nth item or a default value. "
852
852
return next(islice(iterable, n, None), default)
853
853
854
854
def quantify(iterable, pred=bool):
855
855
"Given a predicate that returns True or False, count the True results."
856
856
return sum(map(pred, iterable))
857
857
858
858
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. "
860
860
g = groupby(iterable)
861
861
return next(g, True) and not next(g, False)
862
862
@@ -873,6 +873,30 @@ which incur interpreter overhead.
873
873
# first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
874
874
return next(filter(pred, iterable), default)
875
875
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
+
876
900
def iter_index(iterable, value, start=0, stop=None):
877
901
"Return indices where a value occurs in a sequence or iterable."
878
902
# iter_index('AABCADEAF', 'A') --> 0 1 4 7
@@ -893,31 +917,17 @@ which incur interpreter overhead.
893
917
except ValueError:
894
918
pass
895
919
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)
918
928
919
929
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. "
921
931
# grouper('ABCDEFG', 3, fillvalue='x') --> ABC DEF Gxx
922
932
# grouper('ABCDEFG', 3, incomplete='strict') --> ABC DEF ValueError
923
933
# grouper('ABCDEFG', 3, incomplete='ignore') --> ABC DEF
@@ -932,16 +942,9 @@ which incur interpreter overhead.
932
942
case _:
933
943
raise ValueError('Expected fill, strict, or ignore')
934
944
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
-
943
945
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
945
948
# Recipe credited to George Sakkis
946
949
num_active = len(iterables)
947
950
nexts = cycle(iter(it).__next__ for it in iterables)
@@ -964,11 +967,43 @@ which incur interpreter overhead.
964
967
return filterfalse(pred, t1), filter(pred, t2)
965
968
966
969
def subslices(seq):
967
- "Return all contiguous non-empty subslices of a sequence"
970
+ "Return all contiguous non-empty subslices of a sequence. "
968
971
# subslices('ABCD') --> A AB ABC ABCD B BC BCD C CD D
969
972
slices = starmap(slice, combinations(range(len(seq) + 1), 2))
970
973
return map(operator.getitem, repeat(seq), slices)
971
974
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
+
972
1007
def before_and_after(predicate, it):
973
1008
""" Variant of takewhile() that allows complete
974
1009
access to the remainder of the iterator.
@@ -980,54 +1015,21 @@ which incur interpreter overhead.
980
1015
>>> ' ' .join(remainder) # takewhile() would lose the 'd'
981
1016
'dEfGhI'
982
1017
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.
986
1020
"""
987
1021
it = iter(it)
988
1022
transition = []
1023
+
989
1024
def true_iterator():
990
1025
for elem in it:
991
1026
if predicate(elem):
992
1027
yield elem
993
1028
else:
994
1029
transition.append(elem)
995
1030
return
996
- def remainder_iterator():
997
- yield from transition
998
- yield from it
999
- return true_iterator(), remainder_iterator()
1000
1031
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)
1031
1033
1032
1034
1033
1035
The following recipes have a more mathematical flavor:
@@ -1562,16 +1564,16 @@ The following recipes have a more mathematical flavor:
1562
1564
1563
1565
>>> list (unique_everseen(' AAAABBBCCDAABBB' ))
1564
1566
['A', 'B', 'C', 'D']
1565
- >>> list (unique_everseen(' ABBCcAD' , str .lower ))
1567
+ >>> list (unique_everseen(' ABBCcAD' , str .casefold ))
1566
1568
['A', 'B', 'C', 'D']
1567
- >>> list (unique_everseen(' ABBcCAD' , str .lower ))
1569
+ >>> list (unique_everseen(' ABBcCAD' , str .casefold ))
1568
1570
['A', 'B', 'c', 'D']
1569
1571
1570
1572
>>> list (unique_justseen(' AAAABBBCCDAABBB' ))
1571
1573
['A', 'B', 'C', 'D', 'A', 'B']
1572
- >>> list (unique_justseen(' ABBCcAD' , str .lower ))
1574
+ >>> list (unique_justseen(' ABBCcAD' , str .casefold ))
1573
1575
['A', 'B', 'C', 'A', 'D']
1574
- >>> list (unique_justseen(' ABBcCAD' , str .lower ))
1576
+ >>> list (unique_justseen(' ABBcCAD' , str .casefold ))
1575
1577
['A', 'B', 'c', 'A', 'D']
1576
1578
1577
1579
>>> d = dict (a = 1 , b = 2 , c = 3 )
0 commit comments