2

I am trying to change diagonal elements of a null matrix to 1. So when I formed a matrix by using multiplying list elements [ [ 0 ] * 4 ] * 4 and changed its Diagonal elements to 1, It changed all elements to 1. But when I formed a matrix by using List comprehensions and changed its Diagonal elements to 1, It worked correctly. Below is the implementations mentioned above:


mat1 = [ [ 0 for i in range(4) ]  for j in range( 4 ) ]   #  Using List Comprehensions
mat2 = [ [ 0 ] * 4 ] * 4                                              # Using multiplying list elements


print( mat1 == mat2 )                         # True

for i in range(4):
    mat1[ i ][ i ]=1                             # mat1 =  [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ]
    mat2[ i ][ i ]=1                             # mat2 =  [ [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1] ]


Where I am doing wrong while using matrix formed by multiplying list elements? Or I am misleading some concepts?

Any explanation is appreciated!

Thank you.

2 Answers2

1

This is actually because mat2 contains 4 references to the same list of 4 elements. In every step of your loop you are setting a value in the same list.

When you say [0, 0, 0, 0] * 4 you are just creating a list which contains the same list four times. This means there are only two actual lists in play.

When you say [[0, 0, 0, 0] for i in [0, 1, 2, 3]] you create a new list with every iteration. This means there are five actual lists in play.

The following snippet should visualize it:

m1 = [[0 for i in range(4)] for j in range(4)]
m2 = [[0] * 4] * 4

for i in range(4):
    m1[i][i] = 1
    m2[i][i] = 1

    print('m1 at i={}: {}'.format(i, m1))
    print('m2 at i={}: {}'.format(i, m2))
    print('')

outputs:

m1 at i=0: [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
m2 at i=0: [[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]

m1 at i=1: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
m2 at i=1: [[1, 1, 0, 0], [1, 1, 0, 0], [1, 1, 0, 0], [1, 1, 0, 0]]

m1 at i=2: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0]]
m2 at i=2: [[1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0]]

m1 at i=3: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
m2 at i=3: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
Samuel Willems
  • 301
  • 3
  • 12
1

This is rather interesting.

mat1 = [ [ 0 for i in range(4) ]  for j in range( 4 ) ]   #  Using List Comprehensions
mat2 = [ [ 0 ] * 4 ] * 4                                              # Using multiplying list elements


print( mat1 == mat2 )                         # True
print( mat1 is mat2 )                         # False

for i in range(4):
    mat1[ i ][ i ]=1                             # mat1 =  [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ]
    mat2[ i ][ i ]=1 

As we can see from the simple test of print(mat1 is mat2) which returned False shows that the variables point to different objects. However print(mat1 == mat2) returns True which occurs if the objects referred to by the variables are equal. Hence in this case, the variables are equal. However the objects are different.

As you can see from mat1, you are actually looping in a nested loop, however for mat2 you are actually referencing to the same array of [0].

You can basically tell if you multiply arrays by doing the following,

mat1 = [1,2,3]
mat2 = mat1*2
print(mat2)

# outputs
[1,2,3,1,2,3]

Axois
  • 1,961
  • 2
  • 11
  • 22