Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I slice each 3x3 submatrix from an arbitrary size matrix?

I want to find each 3x3 submatrix from a bigger matrix. I'm stuck on how to slice each matrix without knowing the size of that matrix. If I know it is a 4x4 matrix, I can slice each submatrix one by one:

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

s1 = [m[0][:3], m[1][:3], m[2][:3]]

s1 = [[1, 5, 9], 
      [0, 4, 6], 
      [6, 1, 8]]

That is only the first 3x3 submatrix out of 4. The matrix can be 3x3, 4x3, 4x4, etc. all the way up to 10x10. Doing it manually for each is definitely out of the question. Is there a way for me to slice each 3x3 submatrix without knowing the size of the bigger matrix?

like image 586
Kingle Avatar asked Jan 26 '26 04:01

Kingle


2 Answers

Matrices are a bit confusing from a human point of view (erm... at least for this human who's answering :-P): when you do m[1][2], the first 1 determines the height (the Y axis, if you may) rather than the width while the subsequent 2 determines the width (the X axis) which is not what we humans are used to.

With that in mind, you could do something like this (note that I changed the sample input m to a 6x5 matrix, just to make sure that a more generic case would work properly).

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

slice_x = 3
slice_y = 3


def test_slice():
    width = len(m[0])
    height = len(m)
    slices = []
    for i in range(0, height - slice_y + 1):
        for j in range(0, width - slice_x + 1):
            slices.append(
                [
                    [m[a][b] for b in range(j, j + slice_x)]
                    for a in range(i, i + slice_y)
                ]
            )
    return slices


if __name__ == "__main__":
    slices = test_slice()
    for sl in slices:
        for row in sl:
            print(row)
        print('------')

Outputs

[1, 5, 9]
[0, 4, 6]
[6, 1, 8]
------
[5, 9, 2]
[4, 6, 1]
[1, 8, 8]
------
[9, 2, 4]
[6, 1, 5]
[8, 8, 6]
------
[2, 4, 7]
[1, 5, 7]
[8, 6, 8]
------
[0, 4, 6]
[6, 1, 8]
[4, 7, 3]
------
[4, 6, 1]
[1, 8, 8]
[7, 3, 5]
------
[6, 1, 5]
[8, 8, 6]
[3, 5, 7]
------
[1, 5, 7]
[8, 6, 8]
[5, 7, 9]
------
[6, 1, 8]
[4, 7, 3]
[8, 9, 6]
------
[1, 8, 8]
[7, 3, 5]
[9, 6, 3]
------
[8, 8, 6]
[3, 5, 7]
[6, 3, 1]
------
[8, 6, 8]
[5, 7, 9]
[3, 1, 1]
------

I believe this would work as long as your slice_x and slice_y are smaller than the width and the height respectively. Play with the values of slice_x and slice_y, and make sure it does what you want.

like image 146
BorrajaX Avatar answered Jan 28 '26 16:01

BorrajaX


[[m[i][j:j+3], m[i+1][j:j+3], m[i+2][j:j+3]] for j in range(len(m[0])-2) for i in range(len(m)-2)]
like image 30
meggar Avatar answered Jan 28 '26 18:01

meggar