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

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

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


当前回答

如果你可以选择使用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 " > < /脚本>

其他回答

这里有很多好答案!我把它们合并成一个答案,并更新了一些代码以获得更现代的语法:

灵感来自Fawad Ghafoor和Óscar Gómez Alcañiz的俏皮话

function transpose(matrix) {
  return matrix[0].map((col, i) => matrix.map(row => row[i]));
}

function transpose(matrix) {
  return matrix[0].map((col, c) => matrix.map((row, r) => matrix[r][c]));
}

由Andrew Tatomyr设计的函数方法风格

function transpose(matrix) {
  return matrix.reduce((prev, next) => next.map((item, i) =>
    (prev[i] || []).concat(next[i])
  ), []);
}

洛达什/马塞尔的下划线

function tranpose(matrix) {
  return _.zip(...matrix);
}

// Without spread operator.
function transpose(matrix) {
  return _.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]])
}

Vigrant的更简单的Lodash/Underscore解决方案

_.unzip(matrix);

香草的方法

function transpose(matrix) {
  const rows = matrix.length, cols = matrix[0].length;
  const grid = [];
  for (let j = 0; j < cols; j++) {
    grid[j] = Array(rows);
  }
  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      grid[j][i] = matrix[i][j];
    }
  }
  return grid;
}

由伊曼纽尔·萨林根启发的香草ES6方法

function transpose(matrix) {
  for (var i = 0; i < matrix.length; i++) {
    for (var j = 0; j < i; j++) {
      const temp = matrix[i][j];
      matrix[i][j] = matrix[j][i];
      matrix[j][i] = temp;
    }
  }
}

// Using destructing
function transpose(matrix) {
  for (var i = 0; i < matrix.length; i++) {
    for (var j = 0; j < i; j++) {
      [matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]];
    }
  }
}

在这里添加TS版本。

const transpose = <T>(m: Array<Array<T>>): Array<Array<T>> => m[0].map((_, i) => m.map(x => x[i]));

只是使用Array.map的另一个变体。使用索引可以转置矩阵,其中M != N:

// Get just the first row to iterate columns first
var t = matrix[0].map(function (col, c) {
    // For each column, iterate all rows
    return matrix.map(function (row, r) { 
        return matrix[r][c]; 
    }); 
});

转置就是先按列映射元素,再按行映射元素。

您可以通过使用以下方法在不使用循环的情况下实现这一点。

数组 Array.prototype.map Array.prototype.reduce Array.prototype.join String.prototype.split

它看起来非常优雅,它不需要任何依赖,如jQuery的Underscore.js。

function transpose(matrix) {  
    return zeroFill(getMatrixWidth(matrix)).map(function(r, i) {
        return zeroFill(matrix.length).map(function(c, j) {
            return matrix[j][i];
        });
    });
}

function getMatrixWidth(matrix) {
    return matrix.reduce(function (result, row) {
        return Math.max(result, row.length);
    }, 0);
}

function zeroFill(n) {
    return new Array(n+1).join('0').split('').map(Number);
}

缩小

function transpose(m){return zeroFill(m.reduce(function(m,r){return Math.max(m,r.length)},0)).map(function(r,i){return zeroFill(m.length).map(function(c,j){return m[j][i]})})}function zeroFill(n){return new Array(n+1).join("0").split("").map(Number)}

这是我做的一个演示。注意没有循环:-)

// Create a 5 row, by 9 column matrix. var m = CoordinateMatrix(5, 9); // Make the matrix an irregular shape. m[2] = m[2].slice(0, 5); m[4].pop(); // Transpose and print the matrix. println(formatMatrix(transpose(m))); function Matrix(rows, cols, defaultVal) { return AbstractMatrix(rows, cols, function(r, i) { return arrayFill(cols, defaultVal); }); } function ZeroMatrix(rows, cols) { return AbstractMatrix(rows, cols, function(r, i) { return zeroFill(cols); }); } function CoordinateMatrix(rows, cols) { return AbstractMatrix(rows, cols, function(r, i) { return zeroFill(cols).map(function(c, j) { return [i, j]; }); }); } function AbstractMatrix(rows, cols, rowFn) { return zeroFill(rows).map(function(r, i) { return rowFn(r, i); }); } /** Matrix functions. */ function formatMatrix(matrix) { return matrix.reduce(function (result, row) { return result + row.join('\t') + '\n'; }, ''); } function copy(matrix) { return zeroFill(matrix.length).map(function(r, i) { return zeroFill(getMatrixWidth(matrix)).map(function(c, j) { return matrix[i][j]; }); }); } function transpose(matrix) { return zeroFill(getMatrixWidth(matrix)).map(function(r, i) { return zeroFill(matrix.length).map(function(c, j) { return matrix[j][i]; }); }); } function getMatrixWidth(matrix) { return matrix.reduce(function (result, row) { return Math.max(result, row.length); }, 0); } /** Array fill functions. */ function zeroFill(n) { return new Array(n+1).join('0').split('').map(Number); } function arrayFill(n, defaultValue) { return zeroFill(n).map(function(value) { return defaultValue || value; }); } /** Print functions. */ function print(str) { str = Array.isArray(str) ? str.join(' ') : str; return document.getElementById('out').innerHTML += str || ''; } function println(str) { print.call(null, [].slice.call(arguments, 0).concat(['<br />'])); } #out { white-space: pre; } <div id="out"></div>

扩展语法不应该用作push的替代品,它只应该在你不想改变现有数组的时候使用。

算法: 对于每一列,只要检查该列是否在结果矩阵中有一行,如果已经有一行,那么简单地推元素,否则创建一个新的行数组,然后推。

因此,与上面的许多其他解决方案不同,这个解决方案不会一次又一次地创建新数组,而是将相同的数组推入。

另外,花点时间了解Nullish Coalescing Operator的用法。

常量 转置= arr => arr。foreach ((v, i) => (m[i]) ??= [], m[i].push(v))), m), []), 矩阵= [[1,2,3],[1,2,3],[1,2,3]] console.log(转置矩阵)