If I can, I have a modification to your solution:
_sentinel = object()
def minmax(*args, key=None):
args_len = len(args)
if args_len == 0:
fname = minmax.__name__
raise ValueError(f"{fname}() expected 1 argument, got 0")
elif args_len == 1:
seq = args[0]
else:
seq = args
it = iter(seq)
vmax = vmin = next(it, _sentinel)
if vmax is _sentinel:
fname = minmax.__name__
raise ValueError(f"{fname}() arg is an empty sequence")
if key is None:
for val in it:
if val > vmax:
vmax = val
elif val < vmin:
vmin = val
else:
fmax = fmin = key(vmax)
for val in it:
fval = key(val)
if fval > fmax:
fmax = fval
vmax = val
elif fval < fmin:
fmin = fval
vmin = val
return (vmin, vmax)
I know, it’s more verbose and less elegant, but I think it’s more fast for the majority of cases, ie key=None
.
PS: no default
. What must it returns, (default, default)
? Or we have to define a default_min
and a default_max
? Overcomplicated IMHO.