Here's my solution:
def monotonic(it):
run = []
for this in it:
if not run:
pass
elif run[0] < run[-1]:
# Increasing
if this < run[-1]:
yield run
run = []
elif run[-1] < run[0]:
# Decreasing
if run[-1] < this:
run.reverse()
yield run
run = []
run.append(this)
if run:
if run[0] <= run[-1]:
# Increasing
yield run
else:
run.reverse()
yield run
It's short, is a single function, doesn't rely on fancy features (unless you consider subscripting with `-1` or using `yield` fancy). It will work on arbitrary iterators, the input doesn't need to be a sequence. It passes all of eesmith's tests. It uses memory proportional to the longest run in the sequence.The trick I've applied is that we don't explicitly keep track of whether we're increasing, decreasing or undecided. Instead we check the run in progress.