我有一个数组的数组,就像这样:

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

我想把它转置得到下面的数组:

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

用循环来实现这一点并不难:

function transposeArray(array, arrayLength){
    var newArray = [];
    for(var i = 0; i < array.length; i++){
        newArray.push([]);
    };

    for(var i = 0; i < array.length; i++){
        for(var j = 0; j < arrayLength; j++){
            newArray[j].push(array[i][j]);
        };
    };

    return newArray;
}

然而,这看起来很笨重,我觉得应该有更简单的方法来做到这一点。是吗?


当前回答

这个,不仅是一个超级高效的解,而且是一个很短的解。

算法时间复杂度:O(n log n)

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

matrix.every((r, i, a) => (
   r.every((_, j) => (
      j = a.length-j-1,
      [ r[j], a[j][i] ] = [ a[j][i], r[j] ],
      i < j-1
   )), 
   i < length-2
));

console.log(matrix);
/*
Prints:
[
   [1,2,3,4],
   [1,2,3,4],
   [1,2,3,4],
   [1,2,3,4]
]
*/

上面的例子将只进行6次迭代。 对于更大的矩阵,比如100x100,它将进行4900次迭代,这比这里提供的任何其他解决方案快51%。

原理很简单,你只遍历矩阵对角线的上半部分,因为对角线永远不会改变,下对角线的下半部分和上半部分互换了,所以没有理由也遍历它。这样可以节省大量的运行时间,特别是在大型矩阵中。

其他回答

如果你可以选择使用Ramda JS和ES6语法,那么这里有另一种方法来做到这一点:

const ' = = > R.map (c = > R.map (r = > [c], a), R.keys ([0])); console.log(转置([ [1,2,3,4], [5,6,7,8], [9,10,11,12] )));// => [[1,5,9],[2,6,10],[3,7,11],[4,8,12]]] < script src = " https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js " > < /脚本>

我发现上面的答案要么很难读懂,要么太啰嗦,所以我自己写了一个。我认为这是在线性代数中实现转置的最直观的方法,你不做值交换,而只是把每个元素插入到新矩阵的正确位置:

function transpose(matrix) {
  const rows = matrix.length
  const cols = matrix[0].length

  let grid = []
  for (let col = 0; col < cols; col++) {
    grid[col] = []
  }
  for (let row = 0; row < rows; row++) {
    for (let col = 0; col < cols; col++) {
      grid[col][row] = matrix[row][col]
    }
  }
  return grid
}

这个,不仅是一个超级高效的解,而且是一个很短的解。

算法时间复杂度:O(n log n)

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

matrix.every((r, i, a) => (
   r.every((_, j) => (
      j = a.length-j-1,
      [ r[j], a[j][i] ] = [ a[j][i], r[j] ],
      i < j-1
   )), 
   i < length-2
));

console.log(matrix);
/*
Prints:
[
   [1,2,3,4],
   [1,2,3,4],
   [1,2,3,4],
   [1,2,3,4]
]
*/

上面的例子将只进行6次迭代。 对于更大的矩阵,比如100x100,它将进行4900次迭代,这比这里提供的任何其他解决方案快51%。

原理很简单,你只遍历矩阵对角线的上半部分,因为对角线永远不会改变,下对角线的下半部分和上半部分互换了,所以没有理由也遍历它。这样可以节省大量的运行时间,特别是在大型矩阵中。

ES6 1liner为:

let invert = a => a[0].map((col, c) => a.map((row, r) => a[r][c]))

所以和Óscar的一样,但你更愿意顺时针旋转它:

let rotate = a => a[0].map((col, c) => a.map((row, r) => a[r][c]).reverse())

let a = [
    [1,1,1]
    , ["_","_","1"]
]
let b = rotate(a);
let c = rotate(b);
let d = rotate(c);
console.log(`a ${a.join("\na ")}`);
console.log(`b ${b.join("\nb ")}`);
console.log(`c ${c.join("\nc ")}`);
console.log(`d ${d.join("\nd ")}`);

收益率

a 1,1,1 
a _,_,1

b _,1
b _,1
b 1,1 

c 1,_,_
c 1,1,1

d 1,1
d 1,_
d 1,_

我觉得这样可读性更强一点。它使用Array.from,逻辑与使用嵌套循环相同:

Var arr = [ [1,2,3,4], [1,2,3,4], [1,2,3,4] ]; /* * arr[0]。Length = 4 =结果行数 加勒比海盗。长度= 3 =结果cols的个数 * / var result = Array.from({长度:arr[0].)长度},函数(x,行){ 返回Array.from({长度:arr。长度},函数(x, col) { 返回arr (col)(行); }); }); console.log(结果);

如果你在处理长度不等的数组,你需要替换arr[0]。长度与其他东西:

Var arr = [ (1、2), [1,2,3], [1,2,3,4] ]; /* * arr[0]。Length = 4 =结果行数 加勒比海盗。长度= 3 =结果cols的个数 * / var result = Array.from({长度:arr. from)Reduce(函数(max, item){返回item。长度>最大长度?项。长度:max;}, 0)},函数(x,行){ 返回Array.from({长度:arr。长度},函数(x, col) { 返回arr (col)(行); }); }); console.log(结果);