25
25
from math import comb , e , exp , factorial , floor , fsum , log , log1p , perm , tau
26
26
from queue import Empty , Queue
27
27
from random import random , randrange , shuffle , uniform
28
- from operator import itemgetter , mul , sub , gt , lt , le
28
+ from operator import itemgetter , mul , sub , gt , lt
29
29
from sys import hexversion , maxsize
30
30
from time import monotonic
31
31
35
35
UnequalIterablesError ,
36
36
consume ,
37
37
flatten ,
38
+ nth ,
38
39
powerset ,
40
+ sieve ,
39
41
take ,
40
42
unique_everseen ,
41
43
all_equal ,
104
106
'minmax' ,
105
107
'nth_or_last' ,
106
108
'nth_permutation' ,
109
+ 'nth_prime' ,
107
110
'nth_product' ,
108
111
'nth_combination_with_replacement' ,
109
112
'numeric_range' ,
@@ -215,8 +218,8 @@ def first(iterable, default=_marker):
215
218
return item
216
219
if default is _marker :
217
220
raise ValueError (
218
- 'first() was called on an empty iterable, and no '
219
- 'default value was provided.'
221
+ 'first() was called on an empty iterable, '
222
+ 'and no default value was provided.'
220
223
)
221
224
return default
222
225
@@ -237,15 +240,14 @@ def last(iterable, default=_marker):
237
240
if isinstance (iterable , Sequence ):
238
241
return iterable [- 1 ]
239
242
# Work around https://bugs.python.org/issue38525
240
- elif hasattr (iterable , '__reversed__' ) and ( hexversion != 0x030800F0 ):
243
+ if hasattr (iterable , '__reversed__' ):
241
244
return next (reversed (iterable ))
242
- else :
243
- return deque (iterable , maxlen = 1 )[- 1 ]
245
+ return deque (iterable , maxlen = 1 )[- 1 ]
244
246
except (IndexError , TypeError , StopIteration ):
245
247
if default is _marker :
246
248
raise ValueError (
247
- 'last() was called on an empty iterable, and no default was '
248
- 'provided.'
249
+ 'last() was called on an empty iterable, '
250
+ 'and no default value was provided.'
249
251
)
250
252
return default
251
253
@@ -569,8 +571,8 @@ def one(iterable, too_short=None, too_long=None):
569
571
pass
570
572
else :
571
573
msg = (
572
- 'Expected exactly one item in iterable, but got {!r}, { !r}, '
573
- ' and perhaps more.'. format ( first_value , second_value )
574
+ f 'Expected exactly one item in iterable, but got { first_value !r} , '
575
+ f' { second_value !r } , and perhaps more.'
574
576
)
575
577
raise too_long or ValueError (msg )
576
578
@@ -631,13 +633,13 @@ def strictly_n(iterable, n, too_short=None, too_long=None):
631
633
if too_short is None :
632
634
too_short = lambda item_count : raise_ (
633
635
ValueError ,
634
- 'Too few items in iterable (got {})' . format ( item_count ) ,
636
+ f 'Too few items in iterable (got { item_count } )' ,
635
637
)
636
638
637
639
if too_long is None :
638
640
too_long = lambda item_count : raise_ (
639
641
ValueError ,
640
- 'Too many items in iterable (got at least {})' . format ( item_count ) ,
642
+ f 'Too many items in iterable (got at least { item_count } )' ,
641
643
)
642
644
643
645
it = iter (iterable )
@@ -1118,10 +1120,8 @@ def spy(iterable, n=1):
1118
1120
[1, 2, 3, 4, 5]
1119
1121
1120
1122
"""
1121
- it = iter (iterable )
1122
- head = take (n , it )
1123
-
1124
- return head .copy (), chain (head , it )
1123
+ p , q = tee (iterable )
1124
+ return take (n , q ), p
1125
1125
1126
1126
1127
1127
def interleave (* iterables ):
@@ -1558,8 +1558,8 @@ def split_into(iterable, sizes):
1558
1558
[[1], [2, 3], [4], []]
1559
1559
1560
1560
When a ``None`` object is encountered in *sizes*, the returned list will
1561
- contain items up to the end of *iterable* the same way that itertools.slice
1562
- does:
1561
+ contain items up to the end of *iterable* the same way that
1562
+ :func:`itertools.slice` does:
1563
1563
1564
1564
>>> list(split_into([1,2,3,4,5,6,7,8,9,0], [2,3,None]))
1565
1565
[[1, 2], [3, 4, 5], [6, 7, 8, 9, 0]]
@@ -2167,13 +2167,11 @@ def __init__(self, *args):
2167
2167
self ._start , self ._stop , self ._step = args
2168
2168
elif argc == 0 :
2169
2169
raise TypeError (
2170
- 'numeric_range expected at least '
2171
- '1 argument, got {}' .format (argc )
2170
+ f'numeric_range expected at least 1 argument, got { argc } '
2172
2171
)
2173
2172
else :
2174
2173
raise TypeError (
2175
- 'numeric_range expected at most '
2176
- '3 arguments, got {}' .format (argc )
2174
+ f'numeric_range expected at most 3 arguments, got { argc } '
2177
2175
)
2178
2176
2179
2177
self ._zero = type (self ._step )(0 )
@@ -2236,7 +2234,7 @@ def __getitem__(self, key):
2236
2234
else :
2237
2235
raise TypeError (
2238
2236
'numeric range indices must be '
2239
- 'integers or slices, not {}' . format ( type (key ).__name__ )
2237
+ f 'integers or slices, not { type (key ).__name__ } '
2240
2238
)
2241
2239
2242
2240
def __hash__ (self ):
@@ -2277,13 +2275,10 @@ def __reduce__(self):
2277
2275
2278
2276
def __repr__ (self ):
2279
2277
if self ._step == 1 :
2280
- return "numeric_range({}, {})" .format (
2281
- repr (self ._start ), repr (self ._stop )
2282
- )
2283
- else :
2284
- return "numeric_range({}, {}, {})" .format (
2285
- repr (self ._start ), repr (self ._stop ), repr (self ._step )
2286
- )
2278
+ return f"numeric_range({ self ._start !r} , { self ._stop !r} )"
2279
+ return (
2280
+ f"numeric_range({ self ._start !r} , { self ._stop !r} , { self ._step !r} )"
2281
+ )
2287
2282
2288
2283
def __reversed__ (self ):
2289
2284
return iter (
@@ -2307,7 +2302,7 @@ def index(self, value):
2307
2302
if r == self ._zero :
2308
2303
return int (q )
2309
2304
2310
- raise ValueError ("{ } is not in numeric range". format ( value ) )
2305
+ raise ValueError (f" { value } is not in numeric range" )
2311
2306
2312
2307
def _get_by_index (self , i ):
2313
2308
if i < 0 :
@@ -2781,7 +2776,7 @@ def __len__(self):
2781
2776
return len (self ._target )
2782
2777
2783
2778
def __repr__ (self ):
2784
- return '{}({})' . format ( self .__class__ .__name__ , repr ( self ._target ))
2779
+ return f' { self .__class__ .__name__ } ( { self ._target !r } )'
2785
2780
2786
2781
2787
2782
class seekable :
@@ -3443,8 +3438,8 @@ def only(iterable, default=None, too_long=None):
3443
3438
pass
3444
3439
else :
3445
3440
msg = (
3446
- 'Expected exactly one item in iterable, but got {!r}, { !r}, '
3447
- ' and perhaps more.'. format ( first_value , second_value )
3441
+ f 'Expected exactly one item in iterable, but got { first_value !r} , '
3442
+ f' { second_value !r } , and perhaps more.'
3448
3443
)
3449
3444
raise too_long or ValueError (msg )
3450
3445
@@ -3726,9 +3721,11 @@ def feed(i):
3726
3721
reservoir = []
3727
3722
for _ in range (k ):
3728
3723
reservoir .append (feed (0 ))
3729
- if strict and len (reservoir ) < k :
3730
- raise ValueError ('Sample larger than population' )
3731
3724
3725
+ if strict and len (reservoir ) < k :
3726
+ raise ValueError ('Sample larger than population' )
3727
+
3728
+ with suppress (StopIteration ):
3732
3729
W = 1.0
3733
3730
while True :
3734
3731
W *= exp (log (random ()) / k )
@@ -3821,15 +3818,16 @@ def is_sorted(iterable, key=None, reverse=False, strict=False):
3821
3818
3822
3819
The function returns ``False`` after encountering the first out-of-order
3823
3820
item, which means it may produce results that differ from the built-in
3824
- :func:`sorted` function for objects with unusual comparison dynamics.
3825
- If there are no out-of-order items, the iterable is exhausted.
3821
+ :func:`sorted` function for objects with unusual comparison dynamics
3822
+ (like ``math.nan``). If there are no out-of-order items, the iterable is
3823
+ exhausted.
3826
3824
"""
3827
- compare = le if strict else lt
3828
3825
it = iterable if (key is None ) else map (key , iterable )
3829
- it_1 , it_2 = tee (it )
3830
- next (it_2 if reverse else it_1 , None )
3831
-
3832
- return not any (map (compare , it_1 , it_2 ))
3826
+ a , b = tee (it )
3827
+ next (b , None )
3828
+ if reverse :
3829
+ b , a = a , b
3830
+ return all (map (lt , a , b )) if strict else not any (map (lt , b , a ))
3833
3831
3834
3832
3835
3833
class AbortThread (BaseException ):
@@ -4822,8 +4820,8 @@ def outer_product(func, xs, ys, *args, **kwargs):
4822
4820
4823
4821
>>> xs = ['A', 'B', 'A', 'A', 'B', 'B', 'A', 'A', 'B', 'B']
4824
4822
>>> ys = ['X', 'X', 'X', 'Y', 'Z', 'Z', 'Y', 'Y', 'Z', 'Z']
4825
- >>> rows = list (zip(xs, ys))
4826
- >>> count_rows = lambda x, y: rows.count(( x, y))
4823
+ >>> pair_counts = Counter (zip(xs, ys))
4824
+ >>> count_rows = lambda x, y: pair_counts[ x, y]
4827
4825
>>> list(outer_product(count_rows, sorted(set(xs)), sorted(set(ys))))
4828
4826
[(2, 3, 0), (1, 0, 4)]
4829
4827
@@ -4978,3 +4976,23 @@ def doublestarmap(func, iterable):
4978
4976
"""
4979
4977
for item in iterable :
4980
4978
yield func (** item )
4979
+
4980
+
4981
+ def _nth_prime_ub (n ):
4982
+ "Upper bound for the nth prime (counting from 1)."
4983
+ # https://en.wikipedia.org/wiki/Prime-counting_function#Inequalities
4984
+ return n * log (n * log (n )) if n >= 6 else 11.1
4985
+
4986
+
4987
+ def nth_prime (n ):
4988
+ """Return the nth prime (counting from 0).
4989
+
4990
+ >>> nth_prime(0)
4991
+ 2
4992
+ >>> nth_prime(100)
4993
+ 547
4994
+ """
4995
+ if n < 0 :
4996
+ raise ValueError
4997
+ limit = math .ceil (_nth_prime_ub (n + 1 ))
4998
+ return nth (sieve (limit ), n )
0 commit comments