在javascript中将矩阵旋转45度

时间:2014-03-06 21:53:29

标签: javascript matrix rotation

给出像这样的矩阵:

1 2 3
4 5 6
7 8 9

可以表示为二维数组:

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

旋转数组,使其以45度角对角线读取并打印出来:

1
4 2
7 5 3
8 6
9

我花了一些时间提出一个我甚至没有完全直观地理解的解决方案,但它起作用,至少对于3x3和4x4矩阵。我希望看到更合理,更干净的实现。

这是我的解决方案:

arr = [[1,2,3,0],[4,5,6,0],[7,8,9,0], [0,0,0,0]];
// arr[i][j];

transform(arr);

function transform(ar) {
    // the number of lines in our diagonal matrix will always be rows + columns - 1
    var lines = ar.length + ar[0].length - 1;
    // the length of the longest line...
    var maxLen = ~~(ar.length + ar[0].length)/2;
    var start = 1;
    var lengths = [];
    // this for loop creates an array of the lengths of each line, [1,2,3,2,1] in our case
    for (i=0;i<lines; i++) {
        lengths.push(start);
        if (i+1 < maxLen) {
            start++;
        } else {
            start--;
        }
    }
    // after we make each line, we're going to append it to str
    var str = "";
    // for every line
        for(j=0; j<lengths.length; j++) {
            // make a new line
            var line = "";
            // i tried to do it all in one for loop but wasn't able to (idk if it's possible) so here we use a particular for loop while lengths of the lines are increasing
            if (j < maxLen) {
                // lengths[j] is equal to the elements in this line, so the for loop will run that many times and create that many elements
                for(c=0; c<lengths[j]; c++) {
                    // if ar[r][c], the pattern here is that r increases along rows (as we add new lines), and decreases along columns. c stays the same as we add rows, and increases across columns 
                    line += ar[lengths[j]-1-c][c] + " ";
                    // when we've added all the elements we need for this line, add it to str with a line break
                    if (c == lengths[j]-1) { 
                        line += "\n"; str += line; 
                    }

                }
            } else {
                // when we're headed down or decreasing the length of each line
                for (r=0; r<lengths[j]; r++) {
                    // the pattern here tripped me up, and I had to introduce another changing variable j-maxLen (or the distance from the center).  r stays the same as rows increase and decreases across columns.  c increases along rows and decreases across columns
                    line += ar[lengths[j]-r+j-maxLen][j-maxLen+r +1] + " ";
                    // that's all our elements, add the line to str;
                    if (r == lengths[j] -1) {
                        line += "\n"; str += line; 
                    }
                }
            }
        }
        console.log(str);

}

4 个答案:

答案 0 :(得分:2)

主要思想是根据(i,j)i+j索引的原始矩阵进行分区。

这在下面的代码段rotated[i+j].push(arr[i][j])中表示:

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

var summax = arr.length + arr[0].length - 1; // max index of diagonal matrix
var rotated = []; // initialize to an empty matrix of the right size
for( var i=0 ; i<summax ; ++i ) rotated.push([]);
// Fill it up by partitioning the original matrix.
for( var j=0 ; j<arr[0].length ; ++j )
    for( var i=0 ; i<arr.length ; ++i ) rotated[i+j].push(arr[i][j]);
// Print it out.
for( var i=0 ; i<summax ; ++i ) console.log(rotated[i].join(' '))

输出:

1
4 2
7 5 3
8 6
9

在Ruby中

产生相同的输出:

puts arr.transpose.flatten.group_by.with_index { |_,k|
    k.divmod(arr.size).inject(:+) }.values.map { |a| a.join ' ' }

答案 1 :(得分:1)

想法:走对角线和夹子

你可以使用Cantor的对角枚举,见Cantor pairing function, 用于表示集合 N x N 具有与集合 N 相同的基数(即自然数可以一对一映射成对的自然数)并将其与跳过矩形矩阵之外的那些值的条件相结合。

Cantor配对函数 pi 取两个自然数 i j ,即对(i,j)并将其映射到自然数 k

pi : |N x |N -> |N : pi(i, j) = k 

使用反向映射来获取此

pi^-1 : |N -> |N x |N : pi^-1(k) = (i, j)

即。一个列举了“无限矩阵” N x N 的对角线单元格。 因此,计算 k 并应用反函数将给出适当的索引对( i j )以打印旋转的矩阵。

示例:

0->(0, 0)  2->(0, 1) | 5->(0, 2)  9->(0, 3)  . . 
1->(1, 0)  4->(1, 1) | 8->(1, 2)   
3->(2, 0)  7->(2, 2) |
---------------------+ <- clipping for 3 x 2 matrix
6->(3, 0)
.
. 

逆Cantor对函数的计算

对于输入 k ,这些公式给出了对( i j ):

w = floor((sqrt(8*k + 1) - 1) / 2)
t = (w*w + w) / 2
j = k - t
i = w - j

请参阅上面给出的链接以获得推导。

结果算法

从[0,..,给出 m x n 矩阵 A i m - 1]枚举行, n - 1]中的 j 枚举列

  1. k = 0
  2. 开始
  3. 计算相应的索引对( i j
  4. 如果索引 i j 位于矩阵维度 m <内,则打印矩阵值 A [i,j] / em>和 n
  5. 打印一个新行,一旦 i 点击矩阵的顶部,即 i == 0
  6. 增量 k
  7. 继续执行第2步,直到您到达索引对( i j )=( n - 1, n - 1)
  8. JavaScript中的示例实现

    注意:我使用print()函数在MongoDB shell中尝试了这个。

    助手功能

    function sprint(k) {
      var s = '' + k;
      while (s.length < 3) {
        s = ' ' + s;
      }
      return s;
    }
    
    function print_matrix(a) {
      var m = a.row_size;
      var n = a.column_size;
      for (var i = 0; i < m; i++) {
        var s = '';
        for (var j = 0; j < n; j++) {
          s += sprint(a.value[i][j]);
        }
        print(s);
      }
    }
    

    Cantor配对函数的逆;

    // inverse of the Cantor pair function
    function pi_inv(k) {
      var w = Math.floor((Math.sqrt(8*k + 1) - 1) / 2);
      var t = (w*w + w) /2;
      var j = k - t;
      var i = w -j;
      return [i, j];
    }
    

    算法

    // "rotate" matrix a
    function rot(a) {
      var m = a.row_size;
      var n = a.column_size;
      var i_max = m - 1;
      var j_max = n - 1;
      var k = 0;
      var s = '';
      do {
        var ij = pi_inv(k);
        var i = ij[0];
        var j = ij[1];
        if ((i <= i_max) && (j <= j_max)) {
          s += sprint(a.value[i][j]);
        }
        if (i == 0) {
          print(s);
          s = '';
        }
        k += 1
      } while ((i != i_max) || (j != j_max));
      print(s);
    }
    

    使用示例

    // example
    var a = { 
      row_size: 4, 
      column_size: 4, 
      value: [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16] ] 
    };
    print('in:');
    print_matrix(a);
    print('out:');
    rot(a);
    

    4x4矩阵的输出

    in:
      1  2  3  4
      5  6  7  8
      9 10 11 12
     13 14 15 16
    out:
       1
       5  2
       9  6  3
       13 10  7  4
       14 11  8
       15 12
       16
    

    此方法适用于任何m x n矩阵,例如4 x 5:

    in:
      1  2  3  4  5
      6  7  8  9 10
     11 12 13 14 15
     16 17 18 19 20
    out:
      1
      6  2
     11  7  3
     16 12  8  4
     17 13  9  5
     18 14 10
     19 15
     20
    

    或4 x 3:

    in:
      1  2  3
      4  5  6
      7  8  9
     10 11 12
    out:
      1
      4  2
      7  5  3
     10  8  6
     11  9
     12
    

答案 2 :(得分:1)

function transform(ar) {
    var result = [],
        i, x, y, row;
    for (i = 0; i < ar.length; i++) {
        row = [];
        for (x = 0, y = i; y >= 0; x++, y--) {
            row.push(ar[y][x]);
        }
        result.push(row);
    }
    for (i = 1; i < ar[0].length; i++) {
        row = [];
        for (x = i, y = ar[0].length - 1; x < ar[0].length; x++, y--) {
            row.push(ar[y][x]);
        }
        result.push(row);
    }
    return result;
}

这将返回旋转的数组,以便在您使用result.push(row);替换每个console.log(row.join(" "));行时将其打印出来。

答案 3 :(得分:1)

这是我的方法:

var origMatrix = [[1,2,3,4,5], [4,5,6,7,8], [9,10,11,12,13], [14,15,16,17,18], [19,20,21,22,23]];

var maxSize = origMatrix.length;//Presuming all internal are equal!
var rotatedMatrix = [];
var internalArray;
var keyX,keyY,keyArray;
for(var y=0;y<((maxSize * 2)-1);y++){
    internalArray = [];
    for(var x=0;x<maxSize;x++){
        keyX = x;
        keyY = y - x;
        if(keyY > -1){
            keyArray = origMatrix[keyY];
            if(typeof(keyArray) != 'undefined' && typeof(keyArray[keyX]) != 'undefined'){
                internalArray.push(keyArray[keyX]);
            }
        }
    }
    rotatedMatrix.push(internalArray);
}

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

这是JSFiddle的实际操作(打开控制台查看结果)