Home > Enterprise >  script switches two items in list after for loop?
script switches two items in list after for loop?

Time:02-26

I am normalizing items in lists by given numbers so eg:

l = [79, 65, 42, 63, 48, 6, 44, 31, 22, 40, 3] 
v = 79 
l = [1.0, 0.8227848101265823, 0.5316455696202531, 0.7974683544303798, 0.6075949367088608, 0.0759493670886076, 0.5569620253164557, 0.3924050632911392, 0.27848101265822783, 0.5063291139240507, 0.0379746835443038]

for that, I was using the following function:

def normalize(l, n): 
    for i in l: 
        if n == 0: 
            l[l.index(i)] = 0 
        else: l[l.index(i)] = i/n

this worked for all but one list/value combinations:

l =[48, 68, 30, 70, 83, 4, 58, 30, 27, 49, 1] 
v = 83 
l = [0.5783132530120482, 0.8192771084337349, 0.3614457831325301, 0.8433734939759037, 0.012048192771084338, 0.04819277108433735, 0.6987951807228916, 0.3614457831325301, 0.3253012048192771, 0.5903614457831325, 1]

in this last one, results for index 4 and 10 are switched, so that it presents as if 83/83= 0.012 and 1/83 = 1

now - I've already solved the problem by returning a new list instead of altering the one from the global scope, I have however not the slightest clue why this switch was happening and why it only affected this one instance. I thought it might be that the integer 30 appeared twice in the list, but after altering one appearance of it to something else not in the list already, the switch still happened.

I am still fairly new to coding and would love to know what I did wrong!

CodePudding user response:

Looks like you just want to divide each element in the list by some variable except if that variable is zero, set the element to zero.

If that's the case then a simple list comprehension would work:

l = [79, 65, 42, 63, 48, 6, 44, 31, 22, 40, 3] 
v = 79 

def normalise(l, v):
    return [x / v for x in l] if v != 0 else [0.0] * len(l)

print(normalise(l, 0))
print(normalise(l, v))

Output:

[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
[1.0, 0.8227848101265823, 0.5316455696202531, 0.7974683544303798, 0.6075949367088608, 0.0759493670886076, 0.5569620253164557, 0.3924050632911392, 0.27848101265822783, 0.5063291139240507, 0.0379746835443038]

Note:

The function will return a new list - i.e., the input list will not be modified

CodePudding user response:

Olvin's answer shows you a much more Pythonic way to achieve your goal. But you also asked "what you did wrong" so I wanted to post an answer for that.

You are modifying the contents of the list as you go through the loop. When you reach the element 83, you replace it with the value 1. When you reach the value 1 at the end of the list, you call l.index(1) to determine what member of the list to update. This returns the index of the first matching element - which is now index 4. So that is what gets updated. The value in the last position of the list is never modified, so remains 1.

As one commenter stated above, modifying the contents of a list while you are iterating over it is not a good practice, and your case is a good example why.

I also would say that you should avoid the index() method if you can use a more direct way of accessing the members of the list. In this case, if I was going to use an explicit loop, I'd loop over the index values, not the items in the list:

def normalize(l, n): 
    for i in range(len(l)): 
        if n == 0: 
            l[i] = 0 
        else:
            l[i] = l[i]/n

This would avoid the problem because it doesn't rely on the item value to determine the index.

But again, the other answer showing a list comprehension is the better way to handle this in Python.

  • Related