繁体   English   中英

在javascript中将矩阵旋转45度

[英]rotate a matrix 45 degrees in javascript

给定这样的矩阵:

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

}

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

这在以下rotated[i+j].push(arr[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 ' ' }

想法:走对角线和剪辑

你可以使用从康托尔对角线枚举,请参阅康托尔配对功能 ,这是用来表明该组N×N具有相同的基数为集合N(即自然数可以一一映射到对自然数)和将其与一种条件相结合,即跳过那些位于矩形矩阵之外的值。

Cantor配对函数pi接受两个自然数ij ,即对(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进行计数并应用反函数将给出正确的索引对( ij ),用于打印旋转矩阵。

例:

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

逆康托对函数的计算

对于输入k,这些公式给出对( ij ):

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

参见上面给出的链接进行推导。

结果算法

给定一个m×n矩阵A:i [0,...,M - 1]列举的行中,并且j[0,..,N - 1]枚举列

  1. k = 0开始
  2. 计算相应的索引对( ij
  3. 如果索引ij在矩阵尺寸mn则打印矩阵值A [i,j]
  4. 一旦击中矩阵的顶部,即i == 0,则打印新行
  5. 增量k
  6. 继续执行步骤2,直到到达索引对( ij )=( n -1, n -1)

JavaScript中的示例实现

注意:我在MongoDB shell中使用了它的print()函数进行了尝试。

辅助功能

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

此方法适用于任何mxn矩阵,例如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
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(" "));

这是我的方法:

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 (打开控制台以查看结果)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM