gridproquo
gridproquo

Reputation: 129

Transpose matrix in Python without modules?

I'm trying to tranpose a matrix in Python 3.x without using numpy. For some reason, I'm having problems with the assignment of new_matrix[col_num][row_num]. For example, if I create a new instance of Matrix like test = Matrix([[1,2,3,],[4,5,6],[7,8,9]]), the first time it goes through the inner for loop, new_matrix becomes [[1,None,None],[1,None,None],[1,None,None]] instead of [[1,None,None],[None,None,None],[None,None,None]]. I can't figure out why this is happening and why it's assigning a value to ALL the first elements of lists.

class Matrix:
    def __init__(self, matrix):
        self.matrix = matrix

    def transpose(self):
        new_matrix = [[None] * len(self.matrix[0])] * len(self.matrix)
        row_num = 0
        for row_num in range(len(self.matrix)):
            for col_num in range(len(self.matrix[0])):
                print(new_matrix[col_num][row_num])
                print(new_matrix)

                #assignment assigning more than one variable

                new_matrix[col_num][row_num] = self.matrix[row_num][col_num]

                print(new_matrix[col_num][row_num])
                print(new_matrix)

            col_num = 0
        return new_matrix

Upvotes: 2

Views: 1884

Answers (3)

B. M.
B. M.

Reputation: 18628

new_matrix = [[None] * len(self.matrix[0])] * len(self.matrix)

must be replaced by

new_matrix = [[None for  j in self.matrix[0]] for i in self.matrix] 

This way, all the None will be "differents".

but the shorter way is to directly build the result with extension lists :

MT= [[M[j][i] for j in range(len(M))] for i in range(len(M[0]))]

Upvotes: 2

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476534

That's because you construct the newmatrix with:

new_matrix = [[None] * len(self.matrix[0])] * len(self.matrix)

If you do:

<array-expr> * number

you do not copy that list, you copy the reference. So that means that when you manipulate newmatrix[0] you also manipulate newmatrix[1], etc.

You should solve it with list-comprehension:

new_matrix = [[None] * len(self.matrix[0]) for _ in range(len(self.matrix))]

Since here you actually construct a new list for each row.

So the algorithm should look:

class Matrix:
    def __init__(self, matrix):
        self.matrix = matrix

    def transpose(self):
        new_matrix = [[None] * len(self.matrix[0]) for _ in range(len(self.matrix))]
        row_num = 0
        for row_num in range(len(self.matrix)):
            for col_num in range(len(self.matrix[0])):
                print(new_matrix[col_num][row_num])
                print(new_matrix)

                #assignment assigning more than one variable

                new_matrix[col_num][row_num] = self.matrix[row_num][col_num]

                print(new_matrix[col_num][row_num])
                print(new_matrix)

            col_num = 0
        return new_matrix

Upvotes: 2

Eli Bendersky
Eli Bendersky

Reputation: 273376

Here's a hint:

In [9]: arr = [[None] * 2] * 3

In [10]: arr
Out[10]: [[None, None], [None, None], [None, None]]

In [11]: arr[1][1] = 2

In [12]: arr
Out[12]: [[None, 2], [None, 2], [None, 2]]

Do you see the problem?

The list replication (* operator) repeats the same nested list object within the containing list. Instead, you should be creating a new list every time.

Upvotes: 1

Related Questions