News for hackers. Stuff that matters.
Re:Pythonic monotonic by mrtranscendence on Friday August 13, 2021 @03:06PM (#28173080)
I couldn't resist.

    import operator as op
    import itertools as it
    
    def mono_split(cmp, lst):
        start = len(list(it.takewhile(lambda t: cmp(t[0], t[1]), zip(lst, lst[1:]))))
        return lst[:start + 1], lst[start + 1:]
    
    def get_mono_splits(lst):
        while len(lst) >= 2:
            if lst[0] == lst[1]:
                yield [lst[0]]
                lst = lst[1:]
            else:
                cmp = op.lt if lst[0] < lst[1] else op.gt
                run, lst = mono_split(cmp, lst)
                yield run
        if len(lst) == 1:
            yield lst
This assumes you're operating on lists and that monotonicity is strict. It's reasonably short, reasonably clear, and uses standard Python modules. Arguably the definition of start in mono_split could be confusing but I don't think it's too bad.
Re:Pythonic monotonic by mrtranscendence on Friday August 13, 2021 @03:14PM (#28173204)
Oops, it doesn't reverse decreasing runs. Make that:

    import operator as op
    import itertools as it
    
    def mono_split(cmp, lst):
        start = len(list(it.takewhile(lambda t: cmp(t[0], t[1]), zip(lst, lst[1:]))))
        return lst[:start + 1], lst[start + 1:]
    
    def get_mono_splits(lst):
        while len(lst) >= 2:
            if lst[0] == lst[1]:
                yield [lst[0]]
                lst = lst[1:]
            else:
                cmp = op.lt if lst[0] < lst[1] else op.gt
                run, lst = mono_split(cmp, lst)
                if cmp == op.gt:
                    run = list(reversed(run))
                yield run
        if len(lst) == 1:
            yield lst