If I have a matrix like this:
matrix = [[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]]
how can I get this:
matrix = [[1, 2, 3, 4],
[5, 6, 10, 14],
[9, 7, 11, 15],
[13, 8, 12, 16]]
That is, how can I exclude the first row and the first column and transpose the rest?
I tried this, it leaves the matrix unchanged:
for i in range(1, 4):
for j in range(1, 4):
temp = copy.deepcopy(matrix[i][j])
matrix[i][j] = matrix[j][i]
matrix[j][i] = temp
And when I try:
new_matrix = list(matrix)
for i in range(1, 4):
for j in range(1, 4):
matrix[i][j] = new_matrix[j][i]
matrix[j][i] = new_matrix[i][j]
I get this:
[[1, 2, 3, 4],
[5, 6, 10, 14],
[9, 10, 11, 15],
[13, 14, 15, 16]]
I want to transpose it over both the main and the secondary diagonal.
When in doubt, write a function.
Ever wondered why Python lacks a built-in function for transposing matrices? It's because zip
does it already. But zip
returns a sequence of tuples, and you need lists, so let's wrap it up.
def transpose(matrix):
return [list(row) for row in zip(*matrix)]
We need to transpose a sub-matrix. How do we extract it?
def submatrix(matrix, skip=1):
return [row[skip:] for row in matrix[skip:]]
It turns out we'll need a function to paste contents of one list over the contents of another, bigger list. The function below assumes that the smaller overlay list never gets past the bounds of the bigger base list, for the sake of simplicity.
def pasteOver(base, overlay, offset):
"""Paste overlay list over base list, starting at offset.
Works even when overlay is not touching either end of base."""
return base[:offset] + overlay + base[(len(overlay)) + offset:]
This picture hopefully helps understand why the indexes in the above code are what they are. The blue part is the overlay
, the longer colored part is base
; the part which will be overlaid is grayed out.
The red part does not occur in your problem, but it's added to make the code a more general solution; it's the base[(len(overlay)) + offset:]
part.
I hope you know how Python's list slicing works.
Now we can paste an entire matrix over another, bigger matrix, by pasting changed rows over it, and pasting a submatrix row over any changed row. Note how the code below is almost a literal translation of the previous sentence.
def graft(matrix, submatrix, offset):
"""Overlays submatrix on matrix at given offset from top/left."""
changing_rows = matrix[offset : offset + len(submatrix)]
changed_rows = [pasteOver(row, sub_row, offset)
for (row, sub_row) in zip(changing_rows, submatrix)]
return pasteOver(matrix, changed_rows, offset)
Now it's easy to combine things to paste a transposed submatrix:
def subTranspose(matrix, skip=1):
sub_transposed = transpose(submatrix(matrix, skip))
return graft(matrix, sub_transposed, skip)
Note how every function is almost comically short and simple, so that "its correctness is painfully obvious" (q). Also note how every function is pure, it never changes the data passed to it or has any other side effects. This code, were it in a real code base, would be easier to read, test, reuse, and maintain.
(But if your matrices are really big, use numpy
anyway.)