Search code examples
pythonpython-3.6

Finding runs of integers


I have a problem that asks me to write a program that has a defined list (as the argument) and will then find all runs of Y consecutive numbers that increase or decrease by 1. It will then return the list of indices of the first element of each of these runs.

For example, if Y = 3, then l1 = [1,2,3,5,10,9,8,9,10,11,7,8,7] returns [0,4,6,7]. I got the code working somewhat, but it only works if I 'hard code' how many numbers I am checking. For example, if Y = 3, then my IF statement is checking l1[i], l1[i] + 1 and l1[i] + 2). I need it to work dynamically no matter what I set Y to.

Below is my code with my 'base logic':

A = [1,2,3,5,10,9,8,9,10,11,7,8,7]

new_indices = []
for index, number in enumerate(A[:-2]):
    urgent_number = abs(A[index + 1])
    next_number = abs(A[index + 2])
    if (number + 1 == urgent_number and number + 2 == next_number) or (number - 1 == urgent_number and number - 2 == next_number):
        new_indices.append(index)

print(new_indices)

Below is my attempt to try and incorporate a while loop to do this dynamically. I'm close, but I just can't seem to figure it out:

A = [1,2,3,5,10,9,8,9,10,11,7,8,7]
Y = 3  #length of list

new_indices = []
for index, number in enumerate(A[:-2]):
    urgent_number = abs(A[index + 1])
    next_number = abs(A[index + 2])
    x = 0
    while x < Y:
        if (number + 1 == urgent_number and number + 2 == next_number) or (number - 1 == urgent_number and number - 2 == next_number):
            new_indices.append(index)
        x += 1

print(new_indices)

prints out [0,0,0,4,4,4,6,6,6,7,7,7]. However, I'm looking for [0,4,6,7].


Solution

  • Since you've gotten all the start indices and just need to remove the duplicates, you can do:

    from itertools import groupby
    
    original_result = [0,0,0,4,4,4,6,6,6,7,7,7]
    final_result = [key for key, _ in groupby(original_result)]
    [key for key, _ in groupby(original_result)]
    

    to get the desired output.

    This outputs:

    [0, 4, 6, 7]
    

    If you need to deal with variable run length specifically, you can find all the valid list slices that could make up a run, and then validate whether or not that slices makes up a run:

    A = [1,2,3,5,10,9,8,9,10,11,7,8,7]
    RUN_LENGTH = 3
    indices = []
    for s in range(len(A) - RUN_LENGTH):
        is_incrementally_increasing = \
            all(i2 - i1 == 1 for i1, i2 in zip(A[s:s+RUN_LENGTH], A[s+1:s+RUN_LENGTH]))
        is_incrementally_decreasing = \
            all(i1 - i2 == 1 for i1, i2 in zip(A[s:s+RUN_LENGTH], A[s+1:s+RUN_LENGTH]))
        if is_incrementally_increasing or is_incrementally_decreasing:
            indices.append(s)
    
    print(indices)
    

    This also outputs:

    [0, 4, 6, 7]