1

I have a problem, where I can't use numpy and for the first time I stumbled across something odd in python.

Here is a minimal example:

a = [[0] * 3] * 3
print(a)
# will output [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
# as expected

a[1][1] = 1
# I expect : [[0, 0, 0], [0, 1, 0], [0, 0, 0]],
# but I get:

print(a)
# will output [[0, 1, 0], [0, 1, 0], [0, 1, 0]]
#                  ?                     ?

How can I create a list of lists, where all the elements are independent from each other?

And if someone bothers, could you explain, what happens there?

  • because you are referencing the same list. Use numpy to create matrices. –  Aug 12 '22 at 13:57
  • The outer `* 3` creates a list that contains three entries, but the problem is that each of these three entries refers to the same object, namely the inner list. So if you address that object and change it, then the two other entries also refer to the changed object. – Robert Haas Aug 12 '22 at 23:28
  • See also [here](https://stackoverflow.com/questions/240178/list-of-lists-changes-reflected-across-sublists-unexpectedly). – Timus Aug 13 '22 at 09:26
  • Well, as I said I can’t use numpy. I’m doing an online course and the auto grader environment for this particular problem doesn’t contain numpy. And I shouldn’t need it to initialise a 2D list. – Grzegorz Lippe Aug 14 '22 at 05:42

4 Answers4

2

What's happening here is that a reference to the same list (the one obtained from [0] * 3) is being placed 3 times in the new list, rather than 3 different lists being placed in it. A way to do what you want is:

a = [[[0] * 3] for _ in range(3)]
Addison Schmidt
  • 374
  • 1
  • 7
  • Ok, but why didn't Python do that in the inner statement? If python creates a reference with the `* n`, so why didn't it behave like this: ```Python a[1][1] = 1 # Output [[1, 1, 1], [1, 1, 1], [1, 1, 1]] ``` – Grzegorz Lippe Aug 15 '22 at 06:07
1

With all below code snippets you can create a 3 * 3 matrix with python:

First method: Appending columns inside of loops for each row

rows = 3
cols = 3

lst = []
matrix = []
for i in range(rows):
    for j in range(cols):
        lst.append(0)
    matrix.append(lst)
    lst.clear()

print(matrix)
# the output will be: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

matrix[1][1] = 1
print(matrix)
# the output will be: [[0, 0, 0], [0, 1, 0], [0, 0, 0]]

Second method: 1 list comprehension outside and 1 concatenation operation inside

rows = 3
cols = 3
 
matrix = [[0] * cols for _ in range(rows)]

print(matrix)
# the output will be: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

matrix[1][1] = 1
print(matrix)
# the output will be: [[0, 0, 0], [0, 1, 0], [0, 0, 0]]

Third method: 1 list comprehension inside and 1 concatenation operation outside

rows = 3
cols = 3
 
matrix = [[0 for _ in range(cols)]] * rows

print(matrix)
# the output will be: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

matrix[1][1] = 1
print(matrix)
# the output will be: [[0, 0, 0], [0, 1, 0], [0, 0, 0]]

Fourth method: Using numpy package

import numpy as np
 
rows = 3
cols = 3
size = rows*cols
 
matrix = np.array([0]*size).reshape(rows,cols)

print(matrix)
# the output will be: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

matrix[1][1] = 1
print(matrix)
# the output will be: [[0, 0, 0], [0, 1, 0], [0, 0, 0]]
Javad
  • 2,033
  • 3
  • 13
  • 23
1

Here's how I'd do it without using * but replacing it with list comprehensions:

a = [[0 for _ in range(3)] for _ in range(3)]
Robert Haas
  • 615
  • 2
  • 8
0
a = list()
n = 3
for i in range(n):
  a.append([0] * n)
  
a[1][1] = 1
print(a)
Eldellano
  • 5
  • 2