Steve D'Aprano wrote: > On Sat, 7 Jan 2017 01:04 am, Peter Otten wrote: > >> Example: you are looking for the minimum absolute value in a series of >> integers. As soon as you encounter the first 0 it's unnecessary extra >> work to check the remaining values, but the builtin min() will continue. >> >> The solution is a minimum function that allows the user to specify a stop >> value: >> >>>>> from itertools import count, chain >>>>> stopmin(chain(reversed(range(10)), count()), key=abs, stop=0) >> 0 >> >> How would you implement stopmin()? > > That depends on whether you want to stop when you find a value *equal* to > the stop value, or *less than* the stop value, or both. > > It depends on whether you want to check for equality or check for any > arbitrary condition. > > It depends on whether you want the stop value to be included or not. (It > looks like you do want it included.) > > But I'd start with this: > > > # not tested > def stopmin(iterable, key=None, stop=None): > it = iter(iterable) > try: > smallest = next(it) > except StopIteration: > raise ValueError('empty iterable has no minimum') > else: > if key is not None: > keyed_smallest = key(smallest)
Must test for stop here. > if key is None: > for x in iterable: Replace `iterable` with `it` in the for loops. > if x < smallest: > smallest = x > if x == stop: > break > else: > for x in iterable: > y = key(x) > if y < keyed_smallest: > keyed_smallest = y > smallest = x > if y == stop: > break > return smallest The whole distraction started when I wanted to avoid the straight-forward thing ;) As it turns out there is not as much legwork as I expected, particularly as I'm not interested in the no-key branch. > Another possibility is to create a variant of itertools takewhile: > > def takeuntil(predicate, iterable): > # takeuntil(lambda x: x<5, [1,4,6,4,1]) --> 1 4 6 > for x in iterable: > yield x > if predicate(x): > break > > min(takeuntil(lambda x: x == 0, iterable), key=abs) > > > py> from itertools import count, chain > py> iterable = chain(reversed(range(10)), count()) > py> min(takeuntil(lambda x: x == 0, iterable), key=abs) > 0 > py> iterable = chain(range(-9, 10), count()) > py> min(takeuntil(lambda x: x == 0, iterable), key=abs) > 0 -- https://mail.python.org/mailman/listinfo/python-list