27

(disclosure, I'm mostly math illiterate).

I have an array in this format:

var grid = [
  [0,0], [0,1], [0,2], [0,3],
  [1,0], [1,1], [1,2], [1,3],
  [2,0], [2,1], [2,2], [2,3],
  [3,0], [3,1], [3,2], [3,3]
];

I need to "rotate" it by 90deg increments, so it's like this:

var grid = [
  [3,0], [2,0], [1,0], [0,0], 
  [3,1], [2,1], [1,1], [0,1], 
  [3,2], [2,2], [1,2], [0,2], 
  [3,3], [2,3], [1,3], [0,3] 
];

How do I accomplish this in Javascript?

methodofaction
  • 70,885
  • 21
  • 151
  • 164
  • are you trying to do this specifically for a 4x4 matrix, or for any matrix of arbitrary dimensions? – ultranaut Mar 02 '13 at 05:17
  • @Blender: I've tried `grid.map(function(d,i){return [Math.abs(d[1]-3), d[0]]})` which does it for one increment but it's obviously wrong from a math standpoint. – methodofaction Mar 02 '13 at 05:19
  • @ultranaut I need it for arbitrary dimensions. – methodofaction Mar 02 '13 at 05:20
  • is there a mistake in output grid last row ? it should be var grid = [ [3,0], [2,0], [1,0], [0,0], [3,1], [2,1], [1,1], [0,1], [3,2], [2,2], [1,2], [0,2], [3,3], [2,3], [1,3], [0,3] ]; .right ? – rab Mar 02 '13 at 05:22
  • @rab ahhhh yes you're right. Updated question. – methodofaction Mar 02 '13 at 05:25
  • Then I'd think you'd want to set it up as something like `var grid = [[[0,0], [0,1]],[[1,0], [1,1]]]` so that your code has some way to know what the dimensions are, no? – ultranaut Mar 02 '13 at 05:25
  • @ultranaut ah, but the grid will always be squared. – methodofaction Mar 02 '13 at 05:27
  • @Duopixel got it, not completely arbitrary but square – ultranaut Mar 02 '13 at 05:29
  • @methodofaction I know it is a very old question. But I found this really nice explanation in this article. https://medium.com/front-end-weekly/matrix-rotation-%EF%B8%8F-6550397f16ab – Shrabanee Nov 08 '19 at 07:35

5 Answers5

55

Rotating a two dimensional m x n matrix

Those looking for Rotating a two dimensional matrix (a more general case) here is how to do it.

example: Original Matrix:

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

Rotated at 90 degrees:

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

This is done in following way:

matrix[0].map((val, index) => matrix.map(row => row[index]).reverse())

For counter-clockwise rotation (Thanks to @karn-ratana):

matrix[0].map((val, index) => matrix.map(row => row[row.length-1-index]));
Nitin Jadhav
  • 6,495
  • 1
  • 46
  • 48
19

Credit goes to this answer for the actual rotation method.

My method was pretty straightforward. Just determine what the row length was, and then iterate through each item, converting the array index to x/y equivalents and then apply the method used in the linked answer to rotate. Finally I converted the rotated X/Y coordinates back to an array index.

var grid = [
  [0,0], [0,1], [0,2], [0,3],
  [1,0], [1,1], [1,2], [1,3],
  [2,0], [2,1], [2,2], [2,3],
  [3,0], [3,1], [3,2], [3,3]
]; 

var newGrid = [];
var rowLength = Math.sqrt(grid.length);
newGrid.length = grid.length

for (var i = 0; i < grid.length; i++)
{
    //convert to x/y
    var x = i % rowLength;
    var y = Math.floor(i / rowLength);

    //find new x/y
    var newX = rowLength - y - 1;
    var newY = x;

    //convert back to index
    var newPosition = newY * rowLength + newX;
    newGrid[newPosition] = grid[i];
}

for (var i = 0; i < newGrid.length; i++)
{   
    console.log(newGrid[i])
}

The output:

[3, 0] [2, 0] [1, 0] [0, 0]  
[3, 1] [2, 1] [1, 1] [0, 1]  
[3, 2] [2, 2] [1, 2] [0, 2]  
[3, 3] [2, 3] [1, 3] [0, 3]  

Fiddle for the lazy. And a 5x5 grid fiddle to demonstrate that the algorithm works for N grid sizes as long as they are square.

Community
  • 1
  • 1
lmortenson
  • 1,610
  • 11
  • 11
11

These are two function for clockwise and counterclockwise 90-degree rotation:

    function rotateCounterClockwise(a){
        var n=a.length;
        for (var i=0; i<n/2; i++) {
            for (var j=i; j<n-i-1; j++) {
                var tmp=a[i][j];
                a[i][j]=a[j][n-i-1];
                a[j][n-i-1]=a[n-i-1][n-j-1];
                a[n-i-1][n-j-1]=a[n-j-1][i];
                a[n-j-1][i]=tmp;
            }
        }
        return a;
    }

    function rotateClockwise(a) {
        var n=a.length;
        for (var i=0; i<n/2; i++) {
            for (var j=i; j<n-i-1; j++) {
                var tmp=a[i][j];
                a[i][j]=a[n-j-1][i];
                a[n-j-1][i]=a[n-i-1][n-j-1];
                a[n-i-1][n-j-1]=a[j][n-i-1];
                a[j][n-i-1]=tmp;
            }
        }
        return a;
    }
Aryan Firouzian
  • 1,940
  • 5
  • 27
  • 41
2

I don't really need to deal with indices, since I can copy the values from one place to the other, this simplifies the answer a bit:

var grid = [
  [0,0], [0,1], [0,2], [0,3], [0,4],
  [1,0], [1,1], [1,2], [1,3], [1,4],
  [2,0], [2,1], [2,2], [2,3], [2,4],
  [3,0], [3,1], [3,2], [3,3], [3,4],
  [4,0], [4,1], [4,2], [4,3], [4,4]
]; 

var side = Math.sqrt(grid.length);

var rotate = function(d,i){
   return [Math.abs(i % side - side+1), Math.floor(i/side)]
}
grid = grid.map(rotate);

You can see a jsfiddle here: http://jsfiddle.net/KmtPg/

methodofaction
  • 70,885
  • 21
  • 151
  • 164
  • When I change any values in your initial grid with this solution the output doesn't change, do you really not want the input to matter? – lmortenson Mar 02 '13 at 14:56
  • 2
    Yes, those are just coordinates of a grid, but your answer is much more relevant most of the time so I'll accept it. – methodofaction Mar 02 '13 at 15:47
0

This solution will work with any kind of matrix but if it's not nn and the size is nm it will have undefined items in the array (I set it to return null in case of undefined), but it works at the end and you will have a rotated array.

//ES6 function
const rotateMatrix = (matrix) => {
let temp;
for (let i = 1; i < matrix.length; i++) {
    for (let j = 0; j < matrix.length / 2; j++) {
        temp = matrix[i][j];
        matrix[i][j] = matrix[j][i] === undefined ? null : matrix[j][i];
        matrix[j][i] = temp;
    }
}
return matrix;
};

// 3,3 matrix example
console.table(rotateMatrix([[1, 2, 64], [4, 5, 55], [7, 8, 34]]));
// 5*3 matrix example
console.table(rotateMatrix([[1, 2, 64], [4, 5, 55], [7, 8, 34], [10, 15, 65], [22, 24, 56]]));
Hoomi
  • 61
  • 5