1

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.

4
  • 3
    Use numpy, this will make your life easy! Commented Nov 30, 2015 at 1:43
  • numpy can be a large pill to swallow if you're using it for something one off. Though, I do agree if he is going to be doing things like this often. Commented Nov 30, 2015 at 1:46
  • @TimberlakeCoding you use the correct tool for the job. If a module has a function you need, then use it. You don't need to become an expert in every single aspect that the module covers. In this particular case, numpy would be of great use, and learning how to use its matrix class and do transpositions is almost trivial if you know the math behind it. Commented Nov 30, 2015 at 1:50
  • Considering that you are using a two dimensional array as a data structure, create some function which can extract sub-two dimensional arrays from larger ones, and transpose the sub-two dimensional array. Then create a function that can merge the sub-array back in with the larger one and you should be fine. Commented Nov 30, 2015 at 2:14

5 Answers 5

6

Learn numpy, even for this simple task it's worth.

import numpy as np

m=np.array(range(1,17)).reshape(4,4)    
m[1:,1:]=m[1:,1:].transpose()                                                                                     

array([[ 1,  2,  3,  4],
       [ 5,  6, 10, 14],
       [ 9,  7, 11, 15],
       [13,  8, 12, 16]])
Sign up to request clarification or add additional context in comments.

Comments

2

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.

pic

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.)

2 Comments

Thank you! Could you just explain how the pasteOver and graft functions work?
I drew an illustration and added a link; hope this helps.
0
from math import ceil
# get rid of first row and first element in each row
m2 = [x[1:] for x in matrix[1:]]
for i in range(ceil(len(m2)/2)): # just top half of the rows
    for j in range(i, len(m2[i])): # just above the diagonal
        m2[i][j], m2[j][i] = m2[j][i], m2[i][j]
# create list with first element in matrix and rest from m2
m3 = []
for i in range(len(m1)):
    row = [matrix[i][0]]
    row.extend(m2[i]) 
    m3.append(line)
# now all m3 is missing is the first row 
m3.insert(0, matrix[0])

Since you hardcoded the length in the loops you posted, I assume the size will always be 4x4. This code will only work with square matrices.

Comments

0

This isn't the most idiomatic way to solve this problem, but I wanted to address why the attempts in the question didn't work and how to transpose in-place as you were originally trying.

There are a couple problems with this:

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]

First you're assigning matrix[i][j] to matrix[j][i] and then assigning matrix[j][i] back to matrix[i][j], which means both will have the same number at the end.

If you did this, you'd swap them instead:

for i in range(1, 4):
    for j in range(1, 4):
        matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]

This doesn't work either though. It doesn't work because we're swapping each cell twice (except for the diagonals which don't matter anyway).

We could make sure we only swap once by only going to the diagonals. One way to do that would be to only swap if i is less than j (or the other way around):

for i in range(1, 4):
    for j in range(1, 4):
        if i < j:
            matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]

This should also give you the answer you're looking for (if swapping the indexes in-place is acceptable).

Comments

0

You can use

np.vstack([modified_submatrix, not_modified_sumbmatrix])

These can help for your task

1 Comment

Hello and welcome in StackOverflow, and thx for your contribution. This answer will probably not work. When you will have enough reputation, prefer a comment than an answer