Matt
Matt

Reputation: 129

How can I determine if the numbers in a list initially increase (or stay the same) and then decrease (or stay the same) with Python?

For example, the digits of 123431 and 4577852 increase and then decrease. I wrote a code that breaks the numbers into a list and is able to tell if all of the digits increase or if all of the digits decrease, but I don't know how to check for digits increasing then decreasing. How do I extend this?

x = int(input("Please enter a number: "))
y = [int(d) for d in str(x)]
def isDecreasing(y):
    for i in range(len(y) - 1):
        if y[i] < y[i + 1]:
            return False
        return True
if isDecreasing(y) == True or sorted(y) == y:
    print("Yes")

Upvotes: 8

Views: 2662

Answers (3)

EL_DON
EL_DON

Reputation: 1516

Split the list at the maximum value, then take the min/ max of the diff of each side:

import numpy as np

test1 = [1, 2, 3, 4, 5, 8, 7, 3, 1, 0]
test2 = [1, 2, 3, 4, 5, 8, 7, 3, 1, 0, 2, 5]
test3 = [7, 1, 2, 3, 4, 5, 8, 7, 3, 1, 0]
test4 = [1, 2, 3, 4, 5, 8, 8, 7, 3, 1, 0]

def incdec_test(x):
    i = np.array(x).argmax()
    return (np.diff(x[0:i]).min() >= 0) and (np.diff(x[i:-1]).max() <= 0)

for test in [test1, test2, test3, test4]:
    print 'increase then decrease = {}'.format(incdec_test(test))

Results:

increase then decrease = True
increase then decrease = False
increase then decrease = False
increase then decrease = False

Upvotes: 2

wim
wim

Reputation: 363063

Seems like a good opportunity to learn about using itertools and generator pipelines. First we make a few simple, decoupled, and reusable components:

from itertools import tee, groupby

def digits(n):
    """420 -> 4, 2, 0"""
    for char in str(n):
        yield int(char)

def pairwise(iterable):
    """s -> (s0,s1), (s1,s2), (s2, s3), ..."""
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

def deltas(pairs):
    """2 5 3 4 -> 3, -2, 1"""
    for left, right in pairs:
        yield right - left

def directions(deltas):
    """3 2 2 5 6 -> -1, 0, 1, 1"""
    for delta in deltas:
        yield -1 if delta < 0 else +1 if delta > 0 else 0

def deduper(directions):
    """3 2 2 5 6 2 2 2 -> 3, 2, 5, 6, 2"""
    for key, group in groupby(directions):
        yield key

Then we put the pieces together to solve the wider problem of detecting an "increasing then decreasing number":

from itertools import zip_longest

def is_inc_dec(stream, expected=(+1, -1)):
    stream = pairwise(stream)
    stream = deltas(stream)
    stream = directions(stream)
    stream = deduper(stream)
    for actual, expected in zip_longest(stream, expected):
        if actual != expected or actual is None or expected is None:
            return False
    else:
        return True

Usage is like this:

>>> stream = digits(123431)
>>> is_inc_dec(stream)
True

This solution will short-circuit correctly for a number like:

121111111111111111111111111111111111111111111111111...2

I've addressed only the "strictly increasing, and then strictly decreasing" number case. Since this sounds like it might be your homework, I'll leave it as an exercise for you to adapt the code for the "non-decreasing and then non-increasing" case which is mentioned in the question title.

Upvotes: 4

Prune
Prune

Reputation: 77885

Find the maximum element. Break the list into two pieces at that location. Check that the first piece is increasing, the second decreasing.

  • For your second example, 4577852, you find the largest element, 8.
  • Break the list in two: 4577 and 852 (the 8 can go in either list, both, or neither).
  • Check that 4577 is increasing (okay) and 852 is decreasing (also okay).

Is that enough to get you to a solution?

Upvotes: 5

Related Questions