Search a sequence for its minimum and stop as soon as the lowest possible value is found

Antonio Caminero Garcia tonycamgar at gmail.com
Sun Jan 8 19:45:29 EST 2017


On Friday, January 6, 2017 at 6:04:33 AM UTC-8, 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()?
> 
> Currently I raise an exception in the key function:
> 
> class Stop(Exception):
>     pass
> 
> def stopmin(items, key, stop):
>     """
>     >>> def g():
>     ...     for i in reversed(range(10)):
>     ...         print(10*i)
>     ...         yield str(i)
>     >>> stopmin(g(), key=int, stop=5)
>     90
>     80
>     70
>     60
>     50
>     '5'
>     """
>     def key2(value):
>         result = key(value)
>         if result <= stop:
>             raise Stop(value)
>         return result
>     try:
>         return min(items, key=key2)
>     except Stop as stop:
>         return stop.args[0]

This is the simplest version I could come up with. I also like the classic 100% imperative, but it seems that is not trendy between the solutions given :D.

you can test it here https://repl.it/FD5A/0
source code:

from itertools import accumulate

# stopmin calculates the greatest lower bound (infimum). 
# https://upload.wikimedia.org/wikipedia/commons/0/0a/Infimum_illustration.svg 

def takeuntil(pred, seq):
  for item in seq:
    yield item
    if not pred(item):
      break

def stopmin(seq, stop=0):
  drop_ltstop = (item for item in seq if item >= stop)
  min_gen = (min_ for min_ in accumulate(drop_ltstop, func=min))
  return list(takeuntil(lambda x: x!= stop, min_gen))[-1]

seq = [1, 4, 7, -8, 0, 7, -8, 9] # 0 just until zero is generated
seq = [1, 4, 7, -8, 7, -8, 9] # 1 the entire sequence is generated

print(stopmin(seq, stop=0))


More information about the Python-list mailing list