Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function to swap top right and bottom left squares in an n x n matrix

Given an n x n matrix, swap elements situated in two squares : top right and bottom left. As it is more an academic task, we can restrict size to 10x10. Moreover, we can't have extra space and must swap it in place.

F.e. you are given:

0 3 1 2
9 2 3 4
5 6 5 7
7 8 9 9

You need to return:

0 3 5 6
9 2 7 8
1 2 5 7
3 4 9 9

If we have matrix 5x5:

1 2 3 4 5
6 7 8 9 1
3 8 7 5 0
3 1 7 8 5
7 4 3 6 7

We still have to swap 2x2 squares, so the result will be:

1 2 3 3 1
6 7 8 7 4
3 8 7 5 0
4 5 7 8 5
9 1 3 6 7

I've figured out that we'll have two variants of this function depending on matrix size: if n is even or uneven. I've tried to solve this task in two loops but i understand that i just swap elems (it's a variant for an even size):

def Swap4(m,r):
    k = r//2
    if r % 2 != 0:
       for i in range(0, k):
            for j in range(k+1, r):
                t = m[i][j]
                m[i][j] = m[j][i]
                m[j][i] = t
    else:
        for i in range(0, k):
            for j in range(k, r):
                t = m[i][j]
                m[i][j] = m[j][i]
                m[j][i] = t

here k is matrix size n // 2. However, it looks to me that we need a kind of shift in i loop for indices as we swap elems like this:

[0][2] -> [2][0]
[0][3] -> [2][1]
[1][2] -> [3][0]
[1][3] -> [3][1]
like image 871
burnn1k Avatar asked Dec 28 '25 14:12

burnn1k


1 Answers

You don't need a loop, but with a (nested) loop you can avoid having an extra copy of part of the array temporarily, which can matter if your array is enormous and you have memory restrictions that matter.

Note: in a comment, you noted that you couldn't use numpy, something that I missed about your question. I've added a solution with only lists at the end.

Here:

import numpy as np


def swap_quad_copy(m: np.array, n: int) -> None:
    assert (m.shape[0] == m.shape[1]) and n <= m.shape[0] // 2

    o = m.shape[0] - n
    x = m[0:n, o:].copy()
    m[0:n, o:] = m[o:, 0:n]
    m[o:, 0:n] = x


def swap_quad_loop(m: np.array, n: int) -> None:
    assert (m.shape[0] == m.shape[1]) and n <= m.shape[0] // 2

    o = m.shape[0] - n
    for i in range(n):
        for j in range(n):
            m[i, o+j], m[o+i, j] = m[o+i, j], m[i, o+j]


def main():
    m = np.array([[11, 12, 13, 14], [21, 22, 23, 24], [31, 32, 33, 34], [41, 42, 43, 44]])
    print(m)

    swap_quad_copy(m, 2)
    print(m)

    swap_quad_loop(m, 2)
    print(m)


main()

The swap_quad_copy shows how you can copy one quad (the upper right one) to a temporary variable, then overwrite that area with the other quad (the lower left one), and then overwrite the other with the temporary variable.

The swap_quad_loop shows how to do the same thing in place, with a nested loop. This takes a bit more time, but uses less space.

Output:

[[11 12 13 14]
 [21 22 23 24]
 [31 32 33 34]
 [41 42 43 44]]
[[11 12 31 32]
 [21 22 41 42]
 [13 14 33 34]
 [23 24 43 44]]
[[11 12 13 14]
 [21 22 23 24]
 [31 32 33 34]
 [41 42 43 44]]

Note that this doesn't work:

m[0:2, 2:4], m[2:4, 0:2] = m[2:4, 0:2], m[0:2, 2:4]

The reason you can swap single elements but not whole slices is that a single element doesn't get you a reference, and the tuple assignment just becomes a normal variable swap. But the slicing operation returns views of the original array, not copies, and thus the copy ends up overwriting one of the quads, and you end up with duplicate data, something like:

[[11 12 31 32]
 [21 22 41 42]
 [31 32 33 34]
 [41 42 43 44]]

If you limit the problem and solution to only using lists of lists, the swap_quad_loop solution still works with minor changes for the type and looks like this:

def swap_quad_loop2(m: list[list[int]], n: int) -> None:
    assert (all(len(m) == len(xs) for xs in m)) and n <= len(m) // 2

    o = len(m) - n
    for i in range(n):
        for j in range(n):
            m[i][o+j], m[o+i][j] = m[o+i][j], m[i][o+j]


def main():
    xss = [[11, 12, 13, 14], [21, 22, 23, 24], [31, 32, 33, 34], [41, 42, 43, 44]]
    swap_quad_loop2(xss, 2)
    print('\n'.join(map(str, xss)))


main()

Output:

[11, 12, 31, 32]
[21, 22, 41, 42]
[13, 14, 33, 34]
[23, 24, 43, 44]
like image 182
Grismar Avatar answered Dec 30 '25 04:12

Grismar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!