在JavaScript中转置2D数组

cke*_*sch 135 javascript arrays transpose matrix

我有一个数组数组,如:

[
    [1,2,3],
    [1,2,3],
    [1,2,3],
]
Run Code Online (Sandbox Code Playgroud)

我想转置它以获得以下数组:

[
    [1,1,1],
    [2,2,2],
    [3,3,3],
]
Run Code Online (Sandbox Code Playgroud)

使用循环以编程方式执行此操作并不困难:

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;
}
Run Code Online (Sandbox Code Playgroud)

然而,这看起来很笨重,我觉得应该有一种更简单的方法.在那儿?

Faw*_*oor 174

array[0].map((col, i) => array.map(row => row[i]));
Run Code Online (Sandbox Code Playgroud)

mapcallback按顺序为数组中的每个元素调用一次提供的函数,并从结果中构造一个新数组.callback仅对已分配值的数组的索引调用; 对于已删除的索引或从未分配过值的索引,不会调用它.

callback使用三个参数调用:元素的值,元素的索引和要遍历的Array对象.[资源]

  • 这是一个很好的解决方案.但是,如果您关心性能,则应使用OP的原始解决方案(带有错误修复以支持M x N阵列,其中M!= N).[查看此jsPerf](http://jsperf.com/transpose-2d-array) (6认同)
  • @BillyMcKee 在 2019 年和 Chrome 75 `loops` 比 `map` 慢 45%。是的,它正确转置,因此第二次运行返回初始矩阵。 (4认同)
  • 为什么使用array [0] .map而不是array.map? (3认同)
  • array [0] .map因为他想遍历有列的次数很多,所以array.map会遍历有多少行。 (3认同)
  • 如果你在同一个阵列上使用它两次,它会再次回到第一个旋转90'的内部 (2认同)
  • @OlivierPons 转置不会将其旋转 90°。它绕“y = -x”轴翻转 (2认同)

Joe*_*Joe 39

你可以使用underscore.js

_.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]])
Run Code Online (Sandbox Code Playgroud)

  • 这很漂亮 - 同样,对我来说,下划线比jQuery更为必要. (3认同)
  • 非常优雅的解决方案,谢谢你. (2认同)

Mah*_*iha 32

这是我在现代浏览器中的实现(没有依赖):

transpose = m => m[0].map((x,i) => m.map(x => x[i]))
Run Code Online (Sandbox Code Playgroud)

  • 转置矩阵的转置是原始矩阵,参见http://www.math.nyu.edu/~neylon/linalgfall04/project1/dj/proptranspose.htm (16认同)

mar*_*cel 20

用最短的路lodash/ underscorees6:

_.zip(...matrix)
Run Code Online (Sandbox Code Playgroud)

哪里matrix可能是:

const matrix = [[1,2,3], [1,2,3], [1,2,3]];
Run Code Online (Sandbox Code Playgroud)

  • 关闭,但_.unzip(矩阵)更短;) (9认同)
  • 天哪,这是一个简短的解决方案。刚刚了解了 ... 运算符 - 用它来将字符串分解为字母数组...感谢您的回复 (2认同)

Yan*_*Tay 14

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

单人队的灵感来自Fawad GhafoorÓscarGómezAlcañ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]));
}
Run Code Online (Sandbox Code Playgroud)

功能性方法风格由Andrew Tatomyr减少

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

Lodash /下划线的烫发

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

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

香草的方法

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;
}
Run Code Online (Sandbox Code Playgroud)

Emanuel Saringan启发的香草原位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]];
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


Ema*_*gan 9

您只需一次传递就可以在原地进行:

function transpose(arr,arrLen) {
  for (var i = 0; i < arrLen; i++) {
    for (var j = 0; j <i; j++) {
      //swap element[i,j] and element[j,i]
      var temp = arr[i][j];
      arr[i][j] = arr[j][i];
      arr[j][i] = temp;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您的数组不是正方形(例如 2x8),我猜这不起作用 (2认同)
  • 此解决方案更改原始阵列.如果您仍然需要原始阵列,那么此解决方案可能不是您想要的.其他解决方案则会创建一个新阵列. (2认同)

And*_*myr 9

整洁纯净:

[[0, 1], [2, 3], [4, 5]].reduce((prev, next) => next.map((item, i) =>
    (prev[i] || []).concat(next[i])
), []); // [[0, 2, 4], [1, 3, 5]]
Run Code Online (Sandbox Code Playgroud)

在提供空阵列的情况下,先前的解决方案可能导致失败.

这是一个功能:

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

console.log(transpose([[0, 1], [2, 3], [4, 5]]));
Run Code Online (Sandbox Code Playgroud)

更新. 扩展运算符可以更好地编写:

const transpose = matrix => matrix.reduce(($, row) =>
    row.map((_, i) => [...($[i] || []), row[i]]), 
    []
)
Run Code Online (Sandbox Code Playgroud)

  • 我不知道我会更好地称呼该更新。当然,这很聪明,但读起来却是一场噩梦。 (4认同)

Nin*_*olz 7

另一种方法是从外到内迭代数组,并通过映射内部值来减少矩阵。

const
    transpose = array => array.reduce((r, a) => a.map((v, i) => [...(r[i] || []), v]), []),
    matrix = [[1, 2, 3], [1, 2, 3], [1, 2, 3]];

console.log(transpose(matrix));
Run Code Online (Sandbox Code Playgroud)


Ósc*_*ñiz 6

只是另一种变体使用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]; 
    }); 
});
Run Code Online (Sandbox Code Playgroud)

转置的所有内容都是先按列映射元素,然后按行映射.


Kev*_*nle 5

如果您可以选择使用Ramda JS和ES6语法,那么这是另一种方法:

const transpose = a => R.map(c => R.map(r => r[c], a), R.keys(a[0]));

console.log(transpose([
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9, 10, 11, 12]
])); // =>  [[1,5,9],[2,6,10],[3,7,11],[4,8,12]]
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>
Run Code Online (Sandbox Code Playgroud)

  • 同时使用Ramda和ES6来解决此问题的绝佳方法 (2认同)