0

I want to be able to find the index of the end of a monotone decreasing subsequence which starts off at the first index of the list and only goes down in consecutive order. So for example, I may have a list that looks like this:

x = [89, 88, 88, 88, 88, 87, 88] and I want to be able to return 5 because it is the index of the last element of the subsequence [89, 88, 88, 88, 88, 87], where each of the numbers in this subsequence are monotone decreasing and go down consecutively, starting at 89, the first index of the list.

Say for example, I had a list that looked like this: x = [89, 87, 87, 86, 87]. I would want to return 0, because it is the only number that starts with the first index (89) and is monotonic decreasing consecutively (i.e., the next number in the list goes down from the first number by 2). Or if I had a list that looked like this: x = [89, 90, 89, 88], I would want to return 0 because it is the only part of the sequence that is monotone decreasing from the first index of the list.

Sorry for the difficulty in explaining. Thank you in advance for the help!

sos
  • 331
  • 2
  • 8
  • What have you tried so far? This is not a site for people to do your code, for you- – jsbueno Aug 02 '16 at 14:13
  • Give it a shot and if you have trouble post your attempt and the problem you are having. At first glance it seems you want to subtract index i+1 from index i and find where the result is negative - that should be sufficient to solve the problem. – wwii Aug 02 '16 at 14:14
  • For continuous functions _derivatives_ are used to analyze how it changes over domain. Discrete analogue of derivative is a [finite difference](https://en.wikipedia.org/wiki/Finite_difference). It seems like you want to return value based on computed finite difference of your data series. – Łukasz Rogalski Aug 02 '16 at 14:16
  • @jsbueno Your assumption is that this is work or something.. It's actually more of a thought experiment that I came up with in my spare time, and I was thinking of how to solve it, but couldn't come up with a reasonable solution. Should I not ask on stackoverflow if I have a coding question that isn't at all relevant to anything that I'm working on? – sos Aug 02 '16 at 14:20
  • N, my assumptio is that the topic on this site is to answer questions on programs were people have already tried something, and help people with specific catchs in vairosu languages, libraries and etensions. What you want is trivialy resolvable by using a state variable, a for loop, and an if statement, and you are asking for itto be done from scratch. There are other places (even on on the Stack Exchange network) for asking for algorithms from scratch. (But nto for programs from scratch, I think) – jsbueno Aug 02 '16 at 14:25
  • athough yousrs is trivial enough that someone will just answer and score a few points. But that does not make it an on topic question. – jsbueno Aug 02 '16 at 14:26
  • I'm voting to close this question as off-topic because the op is plainy asked the algorithm + code from scratch. – jsbueno Aug 02 '16 at 14:26
  • But that's exactly it -- I've already tried a for loop solution, which I believe is inefficient. It's entirely trivial if you're okay with an inefficient solution. What good is my algorithm if I already know it isn't sufficient? It's a matter of < 10 lines of code that I already know aren't correct. It isn't going to help anyone -- no one will build off code that's trivially short already. Go ahead and vote to end the question.. But if you do, you might as well vote to end all questions that ask for solutions to coding problems that are trivial. – sos Aug 02 '16 at 14:38
  • 2
    @sos If you have a working solution that you think is inefficient, then you should ask (an on-topic questin) at codereview.stackexchange.com. This is not the place to ask for general implementation ideas. – chepner Aug 02 '16 at 14:40
  • 1
    Please note that this question in it's current form is off-topic for Code Review. We are about improving existing, *working* code. – syb0rg Aug 02 '16 at 14:42
  • Why is it that so many others frequently ask for general implementations for non-trivial matters, and these questions are considered on topic? – sos Aug 02 '16 at 14:53
  • And I think in a more general way, this is very much non-conducive to general questions on coding. Go ahead and close the question. Though I believe what makes a question "on topic" isn't that it doesn't ask for general implementations, but rather that it is masked in such a way that it gives people a sense that they aren't being used. – sos Aug 02 '16 at 14:56
  • What would be the desired result for an input of ```[88,88,88]```? – wwii Aug 02 '16 at 16:41
  • What would be the desired result for an input of [88,88,88,87,88]? – wwii Aug 02 '16 at 18:43

4 Answers4

0

I'm not sure I completely understood the question, but take a look at this:

def findseries(a):
    for i in xrange(len(a) - 1):
        if a[i+1] - a[i] not in [-1, 0]:
            return i
    return len(a) - 1

You basically iterate through the list. If the next element you check is not exactly 1 less than the current or equal to it, then we know the current will be the last element in the series.

Otherwise, we continue to the next element.

If we have finished iterating through the whole list without finding any mismatching element, we can say that the last element of the list is the last element of the series, so we return len(a) - 1 - the index of the last element.

Yotam Salmon
  • 2,400
  • 22
  • 36
  • Thank you! Almost what I'm looking for. But I don't necessarily want the last element in the list. Only the last element of the subset of the list that is monotonic decreasing consecutively. – sos Aug 02 '16 at 14:16
  • What do you mean by " But I don't necessarily want the last element in the list"? This function returns the last element of the list only if the whole list is a correct series (monotonic decreasing consecutively) – Yotam Salmon Aug 02 '16 at 14:18
  • This is incorrect. The `if` condition should say `a[i+1]-a[i] not in [-1,0]` – Saurav Gupta Aug 02 '16 at 14:20
  • @SauravGupta Indeed you're right. Fixed :). Forgot that elements can be equal to their previous ;-) – Yotam Salmon Aug 02 '16 at 14:21
  • 2
    A convenient way to iterate over adjacent pairs from a single sequence is: ```for x, y in zip(a, a[1:]):```. – wwii Aug 02 '16 at 14:24
  • @wwii I was going to do that, but thought that the level of the question shows a minimalist knowledge of Python language, so I tried to make it as simple as possible ;-) – Yotam Salmon Aug 02 '16 at 14:27
0

You can use a python generator expression:

x = [89, 88, 88, 88, 88, 87, 88]
g = (i for i,(v,u) in enumerate(zip(x,x[1:])) if not (u+1==v or u==v))
next(g)
#output:
5
Graham
  • 7,431
  • 18
  • 59
  • 84
Ohad Eytan
  • 8,114
  • 1
  • 22
  • 31
  • 1
    Or possibly `next(g, -1)` or `next(g, len(x))`, depending what's supposed to happen in case the whole sequence fits the requirements. – Steve Jessop Aug 02 '16 at 15:01
0

If you want to over-complicate the matter, you can first create a function which generates the pairs of consecutive entries in the iterable:

def consecutive_pairs(iterable):
    it = iter(iterable)
    first = next(it)
    for second in it:
        yield (first, second)
        first = second

Then, you can check whether the difference in each pair is 0 or 1:

def last_decreasing_index(iterable):
    pairs = consecutive_pairs(iterable)
    for index, (first, second) in enumerate(pairs):
        if first - second not in (0, 1):
            return index
    return index + 1 # full sequence is monotonic

There are obviously shorter ways to accomplish the same goal (see the other answers).

Jared Goguen
  • 8,772
  • 2
  • 18
  • 36
0

This works if [88,88,88] produces 2:

def foo(it, n = 0):
    #print(it, n)
    try:
        monotonic = -1 < it[0] - it[1] < 2
        if monotonic:
            n = foo(it[1:], n + 1)
    except IndexError:
        pass
    return n

Refactored for [88,88,88] input producing 0:

def foo(it, n = 0):
    print(it, n)
    try:
        difference = it[0] - it[1]
        if difference == 0 and n == 0:
            pass
        elif -1 < difference < 2:
            n = foo(it[1:], n + 1)
    except IndexError:
        pass
    return n
wwii
  • 23,232
  • 7
  • 37
  • 77