How to modify list entries during for loop?

Python

Python Problem Overview


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?

Python Solutions


Solution 1 - Python

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

See How to remove items from a list while iterating?.

Solution 2 - Python

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)

Solution 3 - Python

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

Solution 4 - Python

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()

Solution 5 - Python

The answer given by Ignacio Vazquez-Abrams is really good. It can be further illustrated by this example. Imagine that:

  1. A list with two vectors is given to you.
  2. 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])]

Solution 6 - Python

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.

Solution 7 - Python

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.

Solution 8 - Python

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']

Solution 9 - Python

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"]]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionalexgolecView Question on Stackoverflow
Solution 1 - PythonmartineauView Answer on Stackoverflow
Solution 2 - PythonIgnacio Vazquez-AbramsView Answer on Stackoverflow
Solution 3 - PythonEugene ShatskyView Answer on Stackoverflow
Solution 4 - PythoncizixsView Answer on Stackoverflow
Solution 5 - PythonRafael MonteiroView Answer on Stackoverflow
Solution 6 - PythonSkurmedelView Answer on Stackoverflow
Solution 7 - PythonNenojView Answer on Stackoverflow
Solution 8 - PythonJorgeView Answer on Stackoverflow
Solution 9 - Pythonsiva balanView Answer on Stackoverflow