0

Given a list say, [4, 5, 5, 1, 8, 3, 1, 6, 2, 7] I want to be able to find the first ascending run in the list.. I want to return the starting position of the list and how long it lasts. So this list would return position 0 and length is 2 (4,5)

If there isn't an ascending run in the list, return -1.

Below is what I have so far but I can't seem to fix the "list index out of range" error I get when I run the program. I know why I get the error but not sure how I can fix it.

import random

def generate_integer_list (num_integers, low_range, high_range):
    assert num_integers > 0, "Value must be greater than 0"
    assert low_range < high_range, "Value must be less than high_range"

    x_range = range(num_integers) #Create a range for the below for-loop
    l = [] #Create an empty list

    #A for loop that goes on for the amount of integers the user wants and
    #generates a number within the bounds, then adds that number to the list we created above
    for _x in x_range:
        r = random.randint(low_range, high_range)

        l.append(r)

    print (l)

    length = len(l)
    for x in range(length   ):
        t = l[x+1] - l[x]

        if t == -1:
            print (True)
        else:
            print (False)


generate_integer_list (5, 0, 10)

What I'm asking is, how can get this function to find the first ascension and return the location as well as the length

l00kitsjake
  • 955
  • 3
  • 11
  • 24
  • You may find the `itertools` module and the code `sublist == sorted(sublist)` useful. – rlms Nov 09 '13 at 21:53
  • 1
    If you're interested in an `itertools` solution, the pattern [here](http://stackoverflow.com/questions/15276156/python-return-lists-of-continuous-integers-from-list) to group runs together may come in handy. – DSM Nov 09 '13 at 22:09

2 Answers2

1

This should do it:

def solve(lis):
    run_length = 0
    ind = 0
    for i, (x, y) in enumerate(zip(lis, lis[1:])):
        if run_length and y-x != 1:
            break
        if y-x == 1:
            if not run_length:
                ind = i
            run_length += 1
    if run_length:
        return run_length+1, ind
    return -1

Demo:

>>> solve([4, 5, 5, 1, 8, 3, 1, 6, 2, 7])
(2, 0)
>>> solve([1, 1, 1, 2, 3, 5, 1, 1])
(3, 2)
>>> solve([1, 1, 1, 1])
-1
>>> solve([1, 2, 5, 6, 7] )
(2, 0)
>>> solve([1, 0, -1, -2, -1, 0, 0])
(3, 3)
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • Tried this for [1, 2, 5, 6, 7] and I get (5,0) which isn't correct. Any ideas how to fix this? I'm trying to fix it now myself. – l00kitsjake Nov 09 '13 at 22:03
  • @JacobMammoliti Incorrect how? Do you want the difference between ascending numbers to be just 1? – Ashwini Chaudhary Nov 09 '13 at 22:05
  • Sorry for being unclear, what it should return is (2, 0). The length should represent the length of the ascension. EDIT: When I mean ascension I mean increasing by one.. I apologize for that. – l00kitsjake Nov 09 '13 at 22:13
1

There are three issues with your code:

  1. Instead of testing whether t == -1, you should test if t is positive. In the example you give, for x=0, t would be 1, and thus the first two elements are ascending.
  2. You should print (or return) False outside the loop. This way you'll go through the whole list before deciding if there isn't an ascending run.
  3. Once you find two ascending numbers, you need to start counting how long the run lasts.

Putting this all together:

length = len(l)
run_started = False
for x in range(length-1):
    t = l[x+1] - l[x]
    if t > 0 :
        if run_started:
            run_length += 1
        else:
            run_started = True
            run_length = 2
    else:
        if run_started:
             print True
             print 'Run length:', run_length
             break
if not run_started:
    print False
mdml
  • 22,442
  • 8
  • 58
  • 66