Loop through a sorted list and find the range that duplicates lie over

Viewed 45

I'm trying to find the range of positions that duplicates lie over in a list. For instance in the list l = [1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 5, 6,7,7, 7] 2 is duplicated between positions 2 and 5. My code works until the very end where an error is caused by what I assume is the inner loop not keeping track of the array's length.

How should I go about in fixing this error?

Code:

l = [1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 5, 6,7,7, 7]

i = 0
out = []
while i < (len(l)):
    ogPos = i
    ogVal = l[i]
    while (l[i] == ogVal):
        print(i)
        i += 1
    edPos = i-1
    print(f'\t{ogPos}\t{edPos}\t{ogVal}')

Output:

0
1
        0       1       1
2
3
4
5
        2       5       2
6
7
8
        6       8       3
9
        9       9       4
10
        10      10      5
11
        11      11      6
12
13
14
Traceback (most recent call last):
  File "testlist.py", line 8, in <module>
    while (l[i] == ogVal):
IndexError: list index out of range
2 Answers

Since the inner loop advances i, it should also check it against the length of the list, like the outer loop does:

while i < (len(l)):
    ogPos = i
    ogVal = l[i]
    while (i < len(l) and l[i] == ogVal): # Here
        print(i)
        i += 1
    edPos = i-1
    print(f'\t{ogPos}\t{edPos}\t{ogVal}')

You don't need the nested loops, and your code could be easier to follow with a for loop. With the nested loop, you need to repeat the length constraint, but you can just have one while loop without the repeated constraint:

>>> l = [1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 5, 6,7,7, 7]
>>> 
>>> i = 0
>>> out = []
>>> ogPos = i
>>> ogVal = l[i]
>>> while i < len(l):
...     print(i)
...     if l[i] != ogVal:
...         edPos = i-1
...         ogPos = i
...         ogVal = l[i]
...         print(f'\t{ogPos}\t{edPos}\t{ogVal}')
...     i += 1
... 
0
1
2
    2   1   2
3
4
5
6
    6   5   3
7
8
9
    9   8   4
10
    10  9   5
11
    11  10  6
12
    12  11  7
13
14

Instead of defining ogPos and ogVal in the outer loop, you can just define it outside of the loop and reset it when you find a change instead of iterating while the numbers are the same.

The for loop version is a bit simpler, simply replacing the while with for i in range(len(l)):

>>> l = [1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 5, 6,7,7, 7]
>>> 
>>> i = 0
>>> out = []
>>> ogPos = i
>>> ogVal = l[i]
>>> for i in range(len(l)):
...     print(i)
...     if l[i] != ogVal:
...         edPos = i-1
...         ogPos = i
...         ogVal = l[i]
...         print(f'\t{ogPos}\t{edPos}\t{ogVal}')
... 
0
1
2
    2   1   2
3
4
5
6
    6   5   3
7
8
9
    9   8   4
10
    10  9   5
11
    11  10  6
12
    12  11  7
13
14
Related