0

I am trying to take a matrix presented in a .txt file and put it into a list. For example a 2x2 matrix would be in a list with the first sublist being the first row and the second sublist being the second row [[a,b],[c,d]]. I was trying to create a matrix list of a certain height by width and fill every value with a 0 and then update a small number of 0s to actual values.

m is a dictionary created from the txt file that looks like this:

{(2, 2): 5, (1, 2): 4, (0, 1): 2, (0, 0): 1, (1, 1): 3, (2, 3): 6}

r is the number of rows for the matrix, indicated in the text file. In this case r is 3

c is the number of columns. c is 4

s is a string for the name of the matrix that will be printed

def print_matrix(m,r,c,s):
    w = sorted(m)
    value_list = []
    matrix_list = []
    for i in range(c-1):
        value_list.append(0)
    for i in range(r):
        matrix_list.append(value_list)
    for i in w:
        matrix_list[i[0]][i[1]] = m[i]
        print(matrix_list)

After reading this topic: Changing an element in one list changes multiple lists ..?. I realize that when I try to edit the list of full of zeroes it changes a value for all rows, not just one row because the sublists are identical. How can I got about creating unique sublist that can be uniquely edited but preserve the ability for the list to have unique number of sublists, and sublist length to correspond to rows and columns?

Patrick Haugh
  • 59,226
  • 13
  • 88
  • 96
Louis
  • 23
  • 2

2 Answers2

0

You are appending the same list instance (value_list) into matrix_list multiple times. This is why when you tried to update a single entry, you updated the value of all sublists at once.

In order to make sure the sublists are different list instances, you'll need to create a new list for each sublist. So if you were do it as a for loop as you did, it would be a nested for loop like so:

# Create a row for each row count
for i in range(r):
    # Create a brand new row 
    value_list = []
    for i in range(c-1):
        value_list.append(0)
    # Push the new row to the matrix
    matrix_list.append(value_list)

However, using your link I have a more condensed representation:

matrix_list = [[0] * (c-1) for k in range(r)]

Put together it would like so:

def print_matrix(m,r,c,s):
    w = sorted(m)
    matrix_list = [[0] * (c-1) for k in range(r)]
    for i in w:
        matrix_list[i[0]][i[1]] = m[i]
        print(matrix_list)

This throws a index out of range error at it's current form, however that's a different problem. :)

Kaiser Dandangi
  • 230
  • 2
  • 8
0

You are running into an aliasing issue. The line

matrix_list.append(value_list)

appends not a copy of the value_list, but a reference to the value_list object. You can circumvent this in a number of ways. The easiest is to simply create a copy of the list when you append it. Using:

matrix_list.append(value_list.copy())

creates a new object, instead of just assigning a reference to an existing object.

Examples:

Here we see an example of aliasing the same list 3 times. When any of the aliases are updated, all of them are changed because they are all the same object.

matrix = []
x = [0,0,0]
for i in range(3):
    matrix.append(x)

matrix
# returns
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

matrix[0][0] = 1
matrix
# returns 
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]

You can instead append a copy of the list, which forces a new object to be created at each row.

matrix = []
x = [0,0,0]
for i in range(3):
    matrix.append(x.copy())  # create a copy

matrix
# returns
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

matrix[0][0] = 1
matrix
# returns 
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]

Only the first row is modified.

James
  • 32,991
  • 4
  • 47
  • 70