2

I'm trying to do a fairly trivial operation in Python, but am stumped as to why I'm getting the error message in the title on the moment_list.remove(moment_list[i]) line. My code is:

for i in range(0,len(moment_list_sum)): 
    if moment_list_sum[i]==nMoments:
        moment_list.remove(moment_list[i])
        LHS.remove(LHS[i])
    else:
        pass

As you can see I am trying to remove the indices from two lists moment_list and LHS that meet the condition in the if loop, of the same indices in the other list being equal to nMoments.

Going into the loop nMoments is an int equal to 3, and the lists are:

LHS                [y_0, y_1, yx1, yx2, yx3, yx4, yx5, yx6, yx7]
moment_list        [[1, 0], [0, 1], [0, 2], [1, 1], [2, 0], [0, 3], [1, 2], [2, 1], [3, 0]]
moment_list_sum    [1, 1, 2, 2, 2, 3, 3, 3, 3]

They are all the same length so I've no idea why I'm getting a list index error, would greatly appreciate any help!!

user124123
  • 1,642
  • 7
  • 30
  • 50
  • 4
    You're breaking the rule of not deleting elements of a list while iterating over it's indices! – Volatility Jun 10 '13 at 10:00
  • Could you post the whole error message, so we can see what caused the exception? – tamasgal Jun 10 '13 at 10:02
  • The whole message is ` File "MEA.py", line 282, in MFK_final moment_list.remove(moment_list[i]) IndexError: list index out of range ` – user124123 Jun 10 '13 at 10:05
  • I'm not changing moment_list_sum I'm using its indices, the ones I'm changing are LHS and moment_list – user124123 Jun 10 '13 at 10:07
  • 1
    @user1987097 you mention that the lengths of the lists are the same, so if you delete an element of any of the lists, you will get an error on the last iteration, because that index won't exist anymore. – Volatility Jun 10 '13 at 10:10

2 Answers2

1

Take this example:

[1, 2, 3, 4, 5]

The length of this list is 5, range(5) = [0,1,2,3,4]

Let's say on the iteration 1 you remove one element. Now the length of the list is 4, yet you will still iterate over the 5th index. In that case, the fifth element no longer exists.

Another issue you could have, this time without generating an error, is element skipping. Taking the same example, you remove the 1. the second element which is 2, is moved to the 0 index and when you iterate to the second index list1 is actually 3, completely skipping to check on the previously second element (2).

A common way to solve this in most computational languages is to iterate over the list backward.

But in python, the best way is actually do a search then a delete operation. First search all the elements that needs to be deleted, store them in a set then remove them from the list, one by one.

Another approach would be to create a filtered list using the itertools filter:

import itertools

ifilter(lambda x: x==nMoments, moment_list_sum)
Samy Arous
  • 6,794
  • 13
  • 20
0

As others have mentioned, you're modifying the length of the lists, so by the time you get to the end, the indexes you're looking at don't exist any more.

Instead, you should build up replacement lists consisting of the elements you need. This would probably work:

LHS, moment_list = zip(*[
    (LHS_elem, moment_list_elem)
    for i, (LHS_elem, moment_list_elem) in enumerate(zip(LHS, moment_list))
    if moment_list_sum[i] != nMoments])

What this does is join the two target lists together, then iterate through them using enumerate to give an index which you use to look up in the third list, then unzip them at the end.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895