8
votes

i have a 6x6 matrix as a list of lists in python. The matrix is divided into 4 square blocks of size 3x3. I want a way to take a transpose of only 1 block. I can do it using the traditional method of going through each element and copying it into another array and back and so on but I want to see if there is a better way, (transposing a matrix in python can be done in one line using the zip method)

for eg this is the representation of the matrix and its blocks

 block 1  block 2
+-------+-------+
| . . . | . . . |
| . . 2 | 1 . . |
| . . . | . . . |
+-------+-------+
| . . . | . . . |
| . . . | . . . |
| . 1 . | . . . |
+-------+-------+
 block 3  block 4

and rotate(3, right) should result in this

 block 1  block 2
+-------+-------+
| . . . | . . . |
| . . 2 | 1 . . |
| . . . | . . . |
+-------+-------+
| . . . | . . . |
| 1 . . | . . . |
| . . . | . . . |
+-------+-------+
 block 3  block 4

I want to find a method that takes in a block number and rotates only that block left or right. Is there any easy way to do it?

4
Should the operation be in place?Sven Marnach
yes, It needs to be in place, or at least, the result needs to be written back to the original matrixrandomThought

4 Answers

5
votes

Building on Sven Marnach's idea to use np.rot90, here is a version which rotates the quadrant clockwise (as requested?). In the key step

block3[:] = np.rot90(block3.copy(),-1)

a copy() is used on the right-hand side (RHS). Without the copy(), as values are assigned to block3, the underlying data used on the RHS is also changed. This muddles the values used in subsquent assignments. Without the copy(), multiple same values are spread about block3.

I don't see a way to do this operation without a copy.

import numpy as np
a = np.arange(36).reshape(6, 6)
print(a)
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [18 19 20 21 22 23]
#  [24 25 26 27 28 29]
#  [30 31 32 33 34 35]]
block3 = a[3:6, 0:3]

# To rotate counterclockwise
block3[:] = np.rot90(block3.copy())
print(a)
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [20 26 32 21 22 23]
#  [19 25 31 27 28 29]
#  [18 24 30 33 34 35]]

# To rotate clockwise
a = np.arange(36).reshape(6, 6)
block3 = a[3:6, 0:3]
block3[:] = np.rot90(block3.copy(),-1)
print(a)
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [30 24 18 21 22 23]
#  [31 25 19 27 28 29]
#  [32 26 20 33 34 35]]
4
votes

For what it's worth, here's how simple this in in NumPy:

>>> a = numpy.arange(36).reshape(6, 6)
>>> a
array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17],
       [18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29],
       [30, 31, 32, 33, 34, 35]])
>>> block3 = a[3:6, 0:3]
>>> block3[:] = numpy.rot90(block3, 1).copy()
>>> a
array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17],
       [20, 26, 32, 21, 22, 23],
       [26, 25, 31, 27, 28, 29],
       [20, 26, 20, 33, 34, 35]])
0
votes

Would it be a solution to define a matrix as a dictionary of blocks and a block as a list of lists? In your example (replace transpose() with the function you use to transpose it):

Matrix={1:block1,2:block2,3:block3,4:block4}
block3=transpose(block3)
Matrix[3]=block3
0
votes

Here is a method to rotate a "Block" from the matrix you have provided:

matrix = [[0,1,2],[3,4,5],[6,7,8]]

def rotate(m, right):
    rm = []
    for i in range(0,len(m)):
        if right:
            rm.append([row[i] for row in reversed(m)])
        else:
            rm.append([row[i] for row in m])
    return rm

right is a Bool
This will return a list of lists

you can also use:

def rotate(m, right):
    if right:
        return list(zip(*reversed(m)))
    else:
        return list(zip(*m))

but this will return a list of tuples


EDIT:

If we are talking about a matrix of type:

matrix = [[[1,2,3],[4,5,6],[7,8,9]], # block 1
          [[1,2,3],[4,5,6],[7,8,9]], # block 2
          [[1,2,3],[4,5,6],[7,8,9]], # block 3
          [[1,2,3],[4,5,6],[7,8,9]]  # block 4
         ]

you would access block 3 by using matrix[2]

so the rotate function would be used like:
rotate(matrix[2], True) #rotate block 3, right