0

Maybe I am just not understanding list indexing correctly, but when I run the following code:

myList= [['nan'] *4]*4  

for i in range(4):
  for j in range(4):
    if [i,j] == [2,1]: 
      myList[i][j]=1
    print('['+str(i)+','+str(j)+']  -->   '+str(myList[i][j]))

I believe it should output

[0][0]  -->   nan
[0][1]  -->   nan
[0][2]  -->   nan
[0][3]  -->   nan
[1][0]  -->   nan
[1][1]  -->   nan
[1][2]  -->   nan
[1][3]  -->   nan
[2][0]  -->   nan
[2][1]  -->   1
[2][2]  -->   nan
[2][3]  -->   nan
[3][0]  -->   nan
[3][1]  -->   nan
[3][2]  -->   nan
[3][3]  -->   nan

However, it actually outputs

[0][0]  -->   nan
[0][1]  -->   nan
[0][2]  -->   nan
[0][3]  -->   nan
[1][0]  -->   nan
[1][1]  -->   nan
[1][2]  -->   nan
[1][3]  -->   nan
[2][0]  -->   nan
[2][1]  -->   1
[2][2]  -->   nan
[2][3]  -->   nan
[3][0]  -->   nan
[3][1]  -->   1
[3][2]  -->   nan
[3][3]  -->   nan

What's more, if I do

myList= [['nan'] *4]*4 

for i in range(4):
  for j in range(4):
    if i==1 and j==2: 
      myList[i][j]=1
    print('['+str(i)+']['+str(j)+']  -->   '+str(myList[i][j]))

I get

[0][0]  -->   nan
[0][1]  -->   nan
[0][2]  -->   nan
[0][3]  -->   nan
[1][0]  -->   nan
[1][1]  -->   nan
[1][2]  -->   1
[1][3]  -->   nan
[2][0]  -->   nan
[2][1]  -->   nan
[2][2]  -->   1
[2][3]  -->   nan
[3][0]  -->   nan
[3][1]  -->   nan
[3][2]  -->   1
[3][3]  -->   nan

Why is it in the first case changing the value at [3][1], and in the later case at [1][2] and [3][2]? The if statement should never be reached for any index except [2][1] in either case! Also, why is are the two if statements not equivalent?

  • When you do `myList= [['nan'] *4]*4` you create the inner list with `['nan'] *4` and then you add this one list 4 times to the outer list. Since all your inner lists are the same list changing a value in one will of course reflect on the others. – Matthias Aug 03 '21 at 19:13

2 Answers2

2

Actually you are correct about indexing, the trouble is with your very first statement.

myList = [['nan'] *4]*4

Each of your inner list ['nan', 'nan', 'nan', 'nan'] is referring to the same object. When you are changing a value in one of the inner lists, this changes your object. As the object changes, all the other inner lists change.

The solution to this problem is simple. Don't use *. This is a pythonic way of solving the problem:

myList = [['nan' for i in range(4)] for i in range(4)]

Un-pythonic way of doing this:

myList = []
for i in range(4):
    myList.append([])
    for j in range(4):
        myList[i].append('nan')
Nothing special
  • 415
  • 3
  • 8
1

Two different issues. The if statements are different because you reversed the order.

if i==1 and j==2: is if [i,j] == [1,2]:

and if [i,j] == [2,1]: is if i==2 and j==1:

As for the other issue.. you're probably not familiar with mutability. The three lists you have inside of the top level list is actually 3 references to the same object.

This question shows how to print a memory address: print memory address of Python variable

Try it on myList, like print(hex(id(myList[0])), 'next', hex(id(myList[1])), 'next', hex(id(myList[1])))

They all have the same address. So when you modify one, it modifies all three, you just don't see the first because you've already gone past it.

ᴓᴓᴓ
  • 1,178
  • 1
  • 7
  • 18