如何在JavaScript中旋转数组中的矩阵

28

披露一下,我基本不懂数学。

我有一个数组,格式如下:

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]
];

我需要将其以90度为增量进行“旋转”,就像这样:
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] 
];

我该如何在Javascript中实现这个?


你是想特别针对4x4矩阵做这个吗,还是适用于任意维度的矩阵? - ultranaut
@Blender:我尝试了grid.map(function(d,i){return [Math.abs(d[1]-3), d[0]]}),它可以进行一次增量,但从数学角度来看显然是错误的。 - methodofaction
@ultranaut 我需要它适用于任意维度。 - methodofaction
那么我认为您希望将其设置为类似 var grid = [[[0,0], [0,1]],[[1,0], [1,1]]] 的东西,以便您的代码有一些方式可以了解尺寸,不是吗? - ultranaut
@methodofaction 我知道这是一个非常古老的问题。但我在这篇文章中发现了一个非常好的解释。https://medium.com/front-end-weekly/matrix-rotation-%EF%B8%8F-6550397f16ab - Shrabanee
显示剩余4条评论
5个回答

57

旋转一个二维的m x n矩阵

如果你正在寻找如何旋转一个二维矩阵(更一般的情况),这里是如何做到的。

示例: 原始矩阵:

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

旋转90度:

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

这是按照以下方式完成的:

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

逆时针旋转(感谢 @karn-ratana):

matrix[0].map((val, index) => matrix.map(row => row[row.length-1-index]));

1
这种方法只适用于方阵。 - Preetham Sridhar
1
@PreethamSridhar 从我的角度来看,我认为这种方法也适用于非方阵,它与矩阵是否为方阵无关。 - Nitin Jadhav
6
逆时针旋转矩阵:matrix[0].map((val, index) => matrix.map(row => row[row.length-1-index])); - Karn Ratana
谢谢@KarnRatana,已将此添加到答案中!干杯。 - Nitin Jadhav
1
这太棒了!与Preetham Sridhar所说的相反,它也适用于矩形形状。顺便说一下,我使用这个算法来旋转单词或块以排列填字游戏。 - Mister Jojo
1
有人可能想加上180,以确保完整。 - undefined

19

这个方法的实际旋转方法是由这个答案提供的。

我的方法非常直接。只需要确定行长度,然后遍历每个项目,将数组索引转换为x/y等效索引,然后应用链接答案中使用的方法进行旋转。最后,我将旋转后的X/Y坐标转换回数组索引。

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])
}

输出:
[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。同时,还有一个5x5网格的fiddle,以演示该算法适用于任何正方形N网格大小。


这是一个非常漂亮的解决方案,简洁而精简。(不过必须是一个方阵) - Noahdecoco
1
“必须是方阵”对我来说是个问题...如果我想旋转一个2x8的矩阵,你会怎么做? - Olivier Pons

11

这里有两个函数用于将图像顺时针和逆时针旋转90度:

    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;
    }

2

我并不需要处理索引,因为我可以将值从一个地方复制到另一个地方,这样会使答案简化一些:

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);

你可以在这里查看一个jsfiddle:http://jsfiddle.net/KmtPg/

当我使用这个解决方案改变你的初始网格中的任何值时,输出并没有发生变化。您真的不想让输入产生影响吗? - lmortenson
2
是的,那些只是网格的坐标,但你的答案大多数情况下更相关,所以我会接受它。 - methodofaction

0

这个解决方案适用于任何类型的矩阵,但是如果它不是nn且大小为nm,数组中将有未定义的项(在这种情况下我设置返回null),但最终它能够正常运行并返回旋转后的数组。

//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]]));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接