简体   繁体   中英

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")

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?

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM