Modify a List While Iterating

Modifying list while iterating

I've been bitten before by (someone else's) "clever" code that tries to modify a list while iterating over it. I resolved that I would never do it under any circumstance.

You can use the slice operator mylist[::3] to skip across to every third item in your list.

mylist = [i for i in range(100)]
for i in mylist[::3]:
print(i)

Other points about my example relate to new syntax in python 3.0.

  • I use a list comprehension to define mylist because it works in Python 3.0 (see below)
  • print is a function in python 3.0

Python 3.0 range() now behaves like xrange() used to behave, except it works with values of arbitrary size. The latter no longer exists.

How to modify list entries during for loop?

It's considered poor form. Use a list comprehension instead, with slice assignment if you need to retain existing references to the list.

a = [1, 3, 5]
b = a
a[:] = [x + 2 for x in a]
print(b)

Modify a list while iterating

You are not modifying the list, so to speak. You are simply modifying the elements in the list. I don't believe this is a problem.

To answer your second question, both ways are indeed allowed (as you know, since you ran the code), but it would depend on the situation. Are the contents mutable or immutable?

For example, if you want to add one to every element in a list of integers, this would not work:

>>> x = [1, 2, 3, 4, 5]
>>> for i in x:
... i += 1
...
>>> x
[1, 2, 3, 4, 5]

Indeed, ints are immutable objects. Instead, you'd need to iterate over the indices and change the element at each index, like this:

>>> for i in range(len(x)):
... x[i] += 1
...
>>> x
[2, 3, 4, 5, 6]

If your items are mutable, then the first method (of directly iterating over the elements rather than the indices) is more efficient without a doubt, because the extra step of indexing is an overhead that can be avoided since those elements are mutable.

In Java, can you modify a List while iterating through it?

There is nothing wrong with the idea of modifying an element inside a list while traversing it (don't modify the list itself, that's not recommended), but it can be better expressed like this:

for (int i = 0; i < letters.size(); i++) {
letters.set(i, "D");
}

At the end the whole list will have the letter "D" as its content. It's not a good idea to use an enhanced for loop in this case, you're not using the iteration variable for anything, and besides you can't modify the list's contents using the iteration variable.

Notice that the above snippet is not modifying the list's structure - meaning: no elements are added or removed and the lists' size remains constant. Simply replacing one element by another doesn't count as a structural modification. Here's the link to the documentation quoted by @ZouZou in the comments, it states that:

A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification

Modifying a list while iterating over it - why not?

while len(mylist) > 0:
print mylist.pop()

You are not iterating over the list. You are each time checking an atomic condition.

Also:

while len(mylist) > 0:

can be rewritten as:

while len(mylist):

which can be rewritten as:

while mylist:

How to modify list elements while iterating over the list?

It certainly is possible to modify a list while iterating over it, you just have to reference the list, not a variable that contains the list value.

for i in range(len(list_1)):
list_1[i] += 1

The difference in the second case is that the variable contains a reference to a mutable container object. You're modifying the contents of that object, not assigning to the variable.

Possible to modify a List while iterating through it?

It's possible, the trick is to iterate backwards:

for (int i = depthCards.Count - 1; i >= 0; i--) {
if (depthCards[i] == something) { // condition to remove element, if applicable
depthCards.RemoveAt(i);
}
}

Best method for changing a list while iterating over it

You can loop over the list backwards, or use a view object.

See https://stackoverflow.com/a/181062/711085 for how to loop over a list backwards. Basically use reversed(yourList) (which happens creates a view object which visits backwards).

If you require indexing, you could do reversed(enumerate(yourList)), but that would effectively create a temporary list in memory because enumerate would need to run before reversed could kick in. You will need to either do index manipulation, or to do this:

for i in xrange(len(yourList)-1, -1, -1):
item = yourList[i]
...

Even cleaner: reversed is aware of range, so you can do this in python3, or in python2 if you use xrange instead:

for i in reversed(range(len(yourList))):  
item = yourList[i]
...

(proof: you can do next(reversed(range(10**10))), but this will crash your computer if using python2)

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)


Related Topics



Leave a reply



Submit