Python: Removing List Element While Iterating Over List

How to remove items from a list while iterating?

You can use a list comprehension to create a new list containing only the elements you don't want to remove:

somelist = [x for x in somelist if not determine(x)]

Or, by assigning to the slice somelist[:], you can mutate the existing list to contain only the items you want:

somelist[:] = [x for x in somelist if not determine(x)]

This approach could be useful if there are other references to somelist that need to reflect the changes.

Instead of a comprehension, you could also use itertools. In Python 2:

from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)

Or in Python 3:

from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)

Python: Removing list element while iterating over list

You could always iterate over a copy of the list, leaving you free to modify the original:

for item in list(somelist):
...
somelist.remove(item)

Python: How to remove elements from list while iterating through it without skipping future iterations

You are right. You need an additional list. But there is an easier solution.

def print_numTXTs(fileList):

counter = 0
for file in list(fileList):
if file.name[-4:] == ".txt":
counter +=1
if file.name == "a.txt":
fileList.remove(file)

The secret is "list(fileList)". You creating an additional list and iterates over this.

Just as powerful are list compressions. In your example it should work like this. I have not tried now...only quickly written here.

fileList = [ file for file in fileList if file.name != "a.txt" ]

How to remove list elements in a for loop in Python?

You are not permitted to remove elements from the list while iterating over it using a for loop.

The best way to rewrite the code depends on what it is you're trying to do.

For example, your code is equivalent to:

for item in a:
print(item)
a[:] = []

Alternatively, you could use a while loop:

while a:
print(a.pop())

I'm trying to remove items if they match a condition. Then I go to next item.

You could copy every element that doesn't match the condition into a second list:

result = []
for item in a:
if condition is False:
result.append(item)
a = result

Alternatively, you could use filter or a list comprehension and assign the result back to a:

a = filter(lambda item:... , a)

or

a = [item for item in a if ...]

where ... stands for the condition that you need to check.

Removing from a list while iterating over it

I debated answering this for a while, because similar questions have been asked many times here. But it's just unique enough to be given the benefit of the doubt. (Still, I won't object if others vote to close.) Here's a visual explanation of what is happening.

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]       <-  b = 0; remove? no
^
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] <- b = 1; remove? yes
^
[0, 2, 3, 4, 5, 6, 7, 8, 9] <- b = 3; remove? no
^
[0, 2, 3, 4, 5, 6, 7, 8, 9] <- b = 4; remove? yes
^
[0, 2, 3, 5, 6, 7, 8, 9] <- b = 6; remove? no
^
[0, 2, 3, 5, 6, 7, 8, 9] <- b = 7; remove? yes
^
[0, 2, 3, 5, 6, 8, 9] <- b = 9; remove? no
^

Since no one else has, I'll attempt to answer your other questions:

Why is no error given to indicate that underlying iterator is being modified?

To throw an error without prohibiting many perfectly valid loop constructions, Python would have to know a lot about what's going on, and it would probably have to get that information at runtime. All that information would take time to process. It would make Python a lot slower, in just the place where speed really counts -- a loop.

Have the mechanics changed from earlier versions of Python with respect to this behaviour?

In short, no. Or at least I highly doubt it, and certainly it has behaved this way since I learned Python (2.4). Frankly I would expect any straightforward implementation of a mutable sequence to behave in just this way. Anyone who knows better, please correct me. (Actually, a quick doc lookup confirms that the text that Mikola cited has been in the tutorial since version 1.4!)

Remove element from list of lists during loop

You need to make copy of original list and then iterate over new copy and remove the items from original list

for item in list(original_list):
...
original_list.remove(item)

In your case, code will look like below

total_read = 0

for i in range(21):
random.shuffle(info)
for index, value in enumerate(list(info)):
b, p, s = value
if len(s) <= i+1:
print("Overshot! Shouldn't see this sentence anymore: %s" % (s))
info.pop(index)
print s[:i+1], i, s

total_read += len(s[i + 1])

Why does removing items from list while iterating over it skip every other item

What happens here is the following:

You start with the following list:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Then, in the first iteration of the for loop, you get the first item of the list which is 0, and remove it from the list. The updated list now looks like:
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Then, at the second iteration of the loop, you get the second item in the updated list. Here, that second item is not 1 anymore but it is 2 (because you look at the updated list), so you remove 2 from the list. The updated list now looks like:
[1, 3, 4, 5, 6, 7, 8, 9]

And it goes on... until you get:
[1, 3, 5, 7, 9]

Delete from a list while iterating

You should use list comprehension and zip and instead of deleting elements from a , instead take elements in a whose b value is over 15. Example -

a[:] = [i for i,j in zip(a,b) if j >=15]

We are using a[:] on the left side, so that a list object gets mutated inplace. (This is different from a = <something> as the latter simply binds name a to a new list whereas former mutates the list inplace).


Demo -

>>> a = [1,2,3,4,5,6,7,8,9]
>>>
>>> b = [10,11,12,13,14,15,16,17,18]
>>> a[:] = [i for i,j in zip(a,b) if j >=15]
>>> a
[6, 7, 8, 9]

Weird behaviour when iterating through list and deleting elements in python

Well, your list is shrinking while you are iterating over it. If you want to, just look at the first element while your iterate over it.

while len(simple_list) > 0:
print(simple_list[0])
del simple_list[0]


Related Topics



Leave a reply



Submit