Home > Software engineering >  Assinging a new value to item in list during for loop doesnt work?
Assinging a new value to item in list during for loop doesnt work?

Time:09-25

I have a list of items. In a for loop i check if the item is 3. And if it is 3 then it should change the 3 to a 2. These are the two ways that came to my mind using a for loop. But only the last one does work.

Is there a way I can make the first for loop work without losing its "pythonic" style?

a = [1, 2, 3]

for num in a:
    if num == 3:
        num = 2
# -> [1, 2, 3]



for i in range(len(a)):
    if a[i] == 3:
        a[i] = 2
# -> [1, 2, 2]

CodePudding user response:

There's no way to assign to a bare name (num) and have it affect a container (list a). You need to use an index. Although, it is more Pythonic to use enumerate:

for i, num in enumerate(a):
    if num == 3:
        a[i] = 2

Another option is to use a full-slice assignment to totally overwrite the contents of the list from a generator expression:

a[:] = (2 if num==3 else num for num in a)

CodePudding user response:

Let's take a look at this code:

for i in [1, 2, 3]:
    ...

In the for loop, the [1, 2, 3] is a list object. The i is just a variable that holds a pointer (basically a reference to the data). When you do an operation like i = 3 in the loop, the variable i is set to hold the number 3, but the actual list is not changed. List comprehension can be used for what you're trying to accomplish:

a = [1, 2, 3]
l = [2 if num == 3 else num for num in a]
# note that this is a ternary operator in a list comprehension

If you wish to use a for loop, then then enumerate method with index assignment will do the trick:

a = [1, 2, 3]
for i, num in enumerate(a):
    if num == 3:
        a[i] = 2

You can also do it manually like so:

i = 0
for num in a:
    if num == 3:
        num[i] = 2
    i  = 1

Note that:

  • list comprehension creates a new list (and doesn't edit the old one)
  • the enumeration method I showed above does edit the original list (but may be slower, this is based on your machine though)
  • the final option I put just to illustrate what the enumerate method does and to show that it is an option

CodePudding user response:

To modify in-place, this is perhaps more Pythonic:

for i, n in enumerate(a):
    if n == 3:
        a[i] = 2

This may also be preferable if you have a lengthy test for how an item is replaced, such that a list comprehension may be unwieldy.

CodePudding user response:

Try a list comprehension:

>>> a = [1, 2, 3]
>>> a = [2 if num == 3 else num for num in a]
>>> a
[1, 2, 2]

CodePudding user response:

If not a list comprehension, you could do use an enumeration:

a = [1,2,3]
for count, num in enumerate(a):
    if num == 3:
        a[count] = 2

A map also works (seriously just use a list comprehension), but it's a bit less pythonic (lambdas are also confusion to some people):

a = [1,2,3]
a = list(map(lambda num: 2 if num==3 else num, a))

Another thing you can do is, if the variable you're iterating over is some object with a method containing side effects (like a setter), you could use that in-place. For example, imagine I have some myInteger class that inherits from int with a method that lets me set some value. Let's say it's something like:

myInt = myInteger(5)
print(myInt.value)
>> 5

myInt.set_value(6)
print(myInt.value)
>>6

This would give you the interface you're looking for:

for num in a:
    if num == 3:
        a.set_value(2)

The trade-off being that you're writing a weird class to do this, which will lead to confusion in the future.

  • Related