[python] How to modify list entries during for loop?

Now I know that it is not safe to modify the list during an iterative looping. However, suppose I have a list of strings, and I want to strip the strings themselves. Does replacement of mutable values count as modification?

This question is related to python

The answer is


In short, to do modification on the list while iterating the same list.

list[:] = ["Modify the list" for each_element in list "Condition Check"]

example:

list[:] = [list.remove(each_element) for each_element in list if each_element in ["data1", "data2"]]

The answer given by Jemshit Iskenderov and Ignacio Vazquez-Abrams is really good. It can be further illustrated with this example: imagine that

a) A list with two vectors is given to you;

b) you would like to traverse the list and reverse the order of each one of the arrays

Let's say you have

v = np.array([1, 2,3,4])
b = np.array([3,4,6])

for i in [v, b]:
    i = i[::-1]   # this command does not reverse the string

print([v,b])

You will get

[array([1, 2, 3, 4]), array([3, 4, 6])]

On the other hand, if you do

v = np.array([1, 2,3,4])
b = np.array([3,4,6])

for i in [v, b]:
   i[:] = i[::-1]   # this command reverses the string

print([v,b])

The result is

[array([4, 3, 2, 1]), array([6, 4, 3])]

One more for loop variant, looks cleaner to me than one with enumerate():

for idx in range(len(list)):
    list[idx]=... # set a new value
    # some other code which doesn't let you use a list comprehension

You can do something like this:

a = [1,2,3,4,5]
b = [i**2 for i in a]

It's called a list comprehension, to make it easier for you to loop inside a list.


Modifying each element while iterating a list is fine, as long as you do not change add/remove elements to list.

You can use list comprehension:

l = ['a', ' list', 'of ', ' string ']
l = [item.strip() for item in l]

or just do the C-style for loop:

for index, item in enumerate(l):
    l[index] = item.strip()

It is not clear from your question what the criteria for deciding what strings to remove is, but if you have or can make a list of the strings that you want to remove , you could do the following:

my_strings = ['a','b','c','d','e']
undesirable_strings = ['b','d']
for undesirable_string in undesirable_strings:
    for i in range(my_strings.count(undesirable_string)):
        my_strings.remove(undesirable_string)

which changes my_strings to ['a', 'c', 'e']


Since the loop below only modifies elements already seen, it would be considered acceptable:

a = ['a',' b', 'c ', ' d ']

for i, s in enumerate(a):
    a[i] = s.strip()

print(a) # -> ['a', 'b', 'c', 'd']

Which is different from:

a[:] = [s.strip() for s in a]

in that it doesn't require the creation of a temporary list and an assignment of it to replace the original, although it does require more indexing operations.

Caution: Although you can modify entries this way, you can't change the number of items in the list without risking the chance of encountering problems.

Here's an example of what I mean—deleting an entry messes-up the indexing from that point on:

b = ['a', ' b', 'c ', ' d ']

for i, s in enumerate(b):
    if s.strip() != b[i]:  # leading or trailing whitespace?
        del b[i]

print(b)  # -> ['a', 'c ']  # WRONG!

(The result is wrong because it didn't delete all the items it should have.)

Update

Since this is a fairly popular answer, here's how to effectively delete entries "in-place" (even though that's not exactly the question):

b = ['a',' b', 'c ', ' d ']

b[:] = [entry for entry in b if entry.strip() == entry]

print(b)  # -> ['a']  # CORRECT

No you wouldn't alter the "content" of the list, if you could mutate strings that way. But in Python they are not mutable. Any string operation returns a new string.

If you had a list of objects you knew were mutable, you could do this as long as you don't change the actual contents of the list.

Thus you will need to do a map of some sort. If you use a generator expression it [the operation] will be done as you iterate and you will save memory.