Python pop function starts over indexing

Question:

I’m trying to remove all instances from a list, for example 9.

I have an ordered list:

num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 10, 11, 12, 13]
arg = 9

I use bisect_left(num, 9), this returns 8 (the first 9 in list). bisect_left uses binary search to return the left most index where a specific value would be placed.

from bisect import bisect_left
num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 10, 11, 12, 13]
arg = 9
index = bisect_left(num, arg)
while(True):
    if(num[index] == arg):
        num.pop(num[index])
        print(num)
        print(num[index])
        print(arg)
    else:
        break

When I run this code whilst debugging I print the list.

[1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 11, 12, 13]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 10, 11, 12, 13]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 11, 12, 13]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 13]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 13]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Of course if I try an do -1 from the index it doesn’t pop anything as it’s looking at the 7th and comparing it to my argument.

When debugging on the 5th increment of the loop it for some reason pops the 9th index instead.

Whilst further debugging I print num[index] and it prints 9 every time.

I’m receiving the error ‘num.pop(num[index])
IndexError: pop index out of range’

Asked By: OttoLuck

||

Answers:

list.pop accepts the index to remove as its argument, not the value.

num.pop(index)

Note that you should change the loop condition to ensure that the index does not go out of bounds. Alternatively, consider using range instead.

while index < len(num):
Answered By: Unmitigated

Rather than repeatedly modifying the list in situ (pop) you could find the low boundary using bisect_left then the high boundary using bisect_right. Consequently slice the original list in two parts to make a new version. For example:

from bisect import bisect_left, bisect_right

num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 10, 11, 12, 13]
arg = 9
lo = bisect_left(num, arg)
hi = bisect_right(num, arg)
num = num[:lo]+num[hi:]
print(num)

Output:

[1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13]
Answered By: DarkKnight

Using bisect is a good idea for a sorted list. You could push it to the limit and get the whole range to remove by using both bisect_left and bisect_right:

from bisect import bisect_left,bisect_right

num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 10, 11, 12, 13]
arg = 9

start,end = bisect_left(num,arg),bisect_right(num,arg)
num[start:end] = []

print(num)
[1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13]
Answered By: Alain T.
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.