0

I am trying to determine the cause of 2 identical lists returning different values when assigning a new value. Provided I have a list, a, when I assert the value of a equals class variable, matrix, I return true. When I change the value of the the first element in each list a and matrix, the lists no longer are equal. What about manipulating the list matrix causes a different result than what is expected?

class Matrix():
    def __init__(self, cells):
        self.cells: int = cells
        self.block: list = [] 
        self.matrix: list = []
        self.empty_block()
        self.create_matrix()

    # empty block
    def empty_block(self):
        self.block = [list(None for row in range(self.cells)) for col in range(self.cells)]

    # matrix of blocks
    def create_matrix(self):
        self.matrix = [list(self.block for row in range(self.cells)) for col in range(self.cells)]

    def insert(self, row, block, sub_column, sub_row, value):
        a = [[[[None, None], [None, None]], [[None, None], [None, None]]], [[[None, None], [None, None]], [[None, None], [None, None]]]]
        print(self.matrix == a)
        a[row][block][sub_column][sub_row] = value
        self.matrix[row][block][sub_column][sub_row] = value
        print(self.matrix == a)
        print(f"a: {a}")
        print(f"b: {self.matrix}")

from matrix import Matrix
matrix = Matrix(2)
matrix.insert(0,0,0,0,1)

The result is:

True
False
a: [[[[1, None], [None, None]], [[None, None], [None, None]]], [[[None, None], [None, None]], [[None, None], [None, None]]]]
b: [[[[1, None], [None, None]], [[1, None], [None, None]]], [[[1, None], [None, None]], [[1, None], [None, None]]]]

The expected result is:

The result is:

True
True
a: [[[[1, None], [None, None]], [[None, None], [None, None]]], [[[None, None], [None, None]], [[None, None], [None, None]]]]
b: [[[[1, None], [None, None]], [[None, None], [None, None]]], [[[None, None], [None, None]], [[None, None], [None, None]]]]

1 Answers1

2

This is a somewhat convoluted version of a much more common list indexing error. In your case, it's a bit subtle because you create the inner array in one place and duplicate it in another. The list that gets copied is self.block, and it's instantiated in self.empty_block(), and it's duplicated into self.matrix when you call self.create_matrix(). I refer you to that other question to understand why this produces the results that you see, but the solution is basically that you need to instantiate a new "block" for each row in the matrix, or you need to create copies of that block for each row. If you simply create a matrix by making a list of a bunch of the same block, then you only really have two arrays, the matrix, and the one block, which is pointed to many times in the matrix. Something like the following should work for you:

# empty block
def create_empty_block(self):
    return [list(None for row in range(self.cells)) for col in range(self.cells)]

# matrix of blocks
def create_matrix(self):
    self.matrix = [list(self.create_empty_block() for row in range(self.cells)) for col in range(self.cells)]
scnerd
  • 5,836
  • 2
  • 21
  • 36