开发者

python: list assignment index out of range

  for row in开发者_如何学编程 c:
    for i in range(len(row)):
      if i not in keep:
        del row[i]

i am getting this error on the last line:

IndexError: list assignment index out of range

i dont understand how it can be out of range if it exists! please help


If row is a list, then don't forget that deleting an element of a list will move all following elements back one place to fill the gap, so all of the later indices into the list will be off-by-one (and each time you delete another element, the error in each index grows by one). There are a few ways to avoid this problem -- to give one, try iterating through the list backwards.

To respond to how to iterate backwards, you could try using the extra parameters you can pass to range. The first two parameters give the range to iterate over (the lower bound being inclusive, and the upper bound exclusive), and the third parameter is the step:

>>> range(5)
[0, 1, 2, 3, 4]
>>> range(0, 5)
[0, 1, 2, 3, 4]
>>> range(3, 5)
[3, 4]
>>> range(3, 5, -1)
[]
>>> range(5, 3, -1)
[5, 4]

So, in your case, it seems you'd want:

range(len(row) - 1, -1, -1)

Or the easier to read (thanks to viraptor):

reversed(range(len(row))

Alternatively, you could try using list comprehensions (I'm assuming c is a list):

for row_number, row in enumerate(c):
    c[row_number] = [x for i, x in enumerate(row) if i in keep]


Maybe you can write it like this

for row in c:
    row[:] = [x for i,x in enumerate(row) if i in keep]


You should not change a list while you are iterating over it to prevent such errors.


The index existed at the start of the loop, but once you have deleted an element, the list is shorter, and does not contain the same number of elements. Thus, your indices may be wrong. If you delete from the end of the list forward, that won't invalidate list indices.

But I'm surprised about this pattern; perhaps there is a better way to solve what you're looking for? Maybe set subtraction or something similar would do what you want to do without modifying a list dozens or hundreds of times.


A more pythonic solution would be to use filter():

>>> keep = {1,3,5}
>>> row = [1, 2, 3, 4]
>>> list(filter(keep.__contains__, row))
[1, 3]

As a filtering function we can use keep.__contains__ which corresponds to the in operator of the set. Because of this we only get items from the row which are in keep.

Note: Use row[:] = filter(keep.__contains__, row) for in-place update of row or a list comprehension: c = [filter(keep.__contains__, row) for row in c]

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜