Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mirroring rows in matrix with loops/recursion?

Given some matrix, I need to mirror all the rows in the matrix. For example

[[2, 1],
[4, 3]]

would become

[[1, 2],
[3, 4]]

I managed to do it for the (2 x 2)-case. But I'm having trouble mirroring something like this:

[[1, 2, 3, 4],
[1, 2, 3, 4]]

This has to become

[[4, 3, 2, 1],
[4, 3, 2, 1]]

I want to do this with loops/recursion. If I use recursion, I would probably have as basic step that the inner most elements get swapped first, and then from here on we would make the matrix bigger by also including the outer elements and swapping them too. However, I'm having trouble with the recursion step. After having swapped the inner most elements, I want to include the next to inner most elements in the matrix, and swap them too, and then continue like this until we reach the outer elements. How can this be implemented in code? This is what I did so far:

matrix = [[1, 2, 3, 4],
          [1, 2, 3, 4]]

def mirror(matrix):
    # This corresponds to the basic step. The two inner most elements get swapped.
    if len(matrix) == 2:
        for i in range(len(matrix)):
            for j in range(len(matrix)):
                # Store one element in a temporal variable
                temp = matrix[i][j]
                matrix[i][j] = matrix[i][len(matrix) - 1]
                matrix[i][len(matrix)-1] = temp
                return matrix

    else:
        # Recursion step
        for i in range(len(matrix)):
            for j in range(len(matrix)):
                return (matrix + mirror(matrix[(len(matrix) // 2) - 1 : len(matrix)]))

The recursion step is wrong I think. I tried using the slice operator, but I'm not sure how this should be done correctly. Any help with this problem would be appreciated.

like image 551
Kamil Avatar asked Dec 05 '15 14:12

Kamil


3 Answers

A recursive solution is pretty trivial, just recurse across the array reversing each subarray:

arr= [[2, 1],
[4, 3]]

def reve(l):
    # if we have recursed across all sub arrays just return empty list
    if not l:
        return []
    # else reverse the first current sublist l[0] and recurse on the remaining sublists 
    return [l[0][::-1]] + reve(l[1:])


print(reve(arr))
[[1, 2], [3, 4]]

Which can be written concisely as:

def reve(l):
    return [l[0][::-1]] + reve(l[1:]) if l else []

If you wanted it inplace:

arr = [[1, 2, 3, 4],
     [1, 2, 3, 4]]

def reve(l):
    if not l:
        return 
    # call inplace list.reverse on each sublist
    l[0].reverse()
    return reve(l[1:])


reve(arr)

Output:

[[4, 3, 2, 1], [4, 3, 2, 1]]

And lastly we can achieve what you want inplace with no slicing at all using iter with the special method __length__hint:

def reve(l):
    if l.__length_hint__() == 0:
        return 
    sub = next(l)
    sub.reverse()
    return reve(l)


reve(iter(arr))

print(arr)

Output:

[[4, 3, 2, 1], [4, 3, 2, 1]]
like image 127
Padraic Cunningham Avatar answered Oct 06 '22 10:10

Padraic Cunningham


Both functions might use the map function, but you can use a imperative for also. About my recursive approach, the else statement refers to all cases between the ultimate and second elements of the list, they are being concatenated until the first element is reached.

My recursive approach:

a = [[1, 2, 3], 
     [5, 6, 7]]

def mirror(matrix):
    def revert(row):
        if len(row) == 1:
            return [row[0]]
        else:
            return [row[-1]] + revert(row[:-1]) # concatenates two lists.

    return [revert(row) for row in matrix]

mirror(a)

My declarative approach:

def mirror(matrix):
    def revert(row):
        return row[::-1] # copies the array in reverse order

    return list(map(revert, matrix)) #<-for python3, and just map(...) for python2

mirror(a)

Both functions outputs

[[3, 2, 1], [7, 6, 5]]

like image 21
Alberto Bonsanto Avatar answered Oct 06 '22 10:10

Alberto Bonsanto


Actually, a more Pythonic way of doing that would be using list comprehensions. You can do that simply by:

matrix = [[1, 2, 3, 4],
      [1, 2, 3, 4]]
reversed_matrix = (i[::-1] for i in matrix)

reversed_matrix will be a generator expression. You may convert it into a list by replacing "()" with "[]" In the list comprehension.

i[::-1] reverses the array in-place using slice operator

like image 22
vessel Avatar answered Oct 06 '22 08:10

vessel