在 JavaScript 中转置二维数组

IT技术 javascript arrays matrix transpose
2021-01-31 09:22:29

我有一组数组,例如:

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

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

6个回答
array[0].map((_, colIndex) => array.map(row => row[colIndex]));

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

callback使用三个参数调用:元素的值、元素的索引和被遍历的 Array 对象。[来源]

@BillyMcKee 在 2019 年和 Chrome 75loopsmap. 是的,它转置正确,所以第二次运行返回初始矩阵。
2021-03-13 09:22:29
如果你在同一个数组上使用它两次,它会回到第一个而不是再次旋转 90'
2021-03-21 09:22:29
这是一个很好的解决方案。但是,如果您关心性能,则应该使用 OP 的原始解决方案(带有错误修复以支持 M x N 数组,其中 M != N)。 检查这个jsPerf
2021-03-23 09:22:29
为什么array[0].map而不是array.map
2021-04-04 09:22:29
array[0].map因为他想迭代多少次有列,array.map会迭代有多少行。
2021-04-07 09:22:29

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

transpose = m => m[0].map((x,i) => m.map(x => x[i]))
转置矩阵的转置是原矩阵,参考math.nyu.edu/~neylon/linalgfall04/project1/dj/proptranspose.htm
2021-03-22 09:22:29
如果你在同一个数组上使用它两次,它会回到第一个而不是再次旋转 90'
2021-04-06 09:22:29

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

灵感来自Fawad GhafoorÓscar Gómez Alcañiz 的One-liners

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

函数式方法风格 with reduce by Andrew Tatomyr

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

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]])
}

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

Emanuel Saringan启发的 Vanilla 就地 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]];
    }
  }
}
@Andy 随时更新答案。任何人都可以编辑它:)
2021-03-29 09:22:29
我认为@vigrant 的答案(只是在评论中)应该包括在这里 - _.unzip 已经做到了
2021-04-06 09:22:29

你可以使用underscore.js

_.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]])
或者如果您正在使用功能库,就像rambda您可以做的那样const transpose = apply(zip)
2021-03-22 09:22:29
这个问题已有多年历史了,现在我不确定是否如此。但是,它比已接受答案原始版本更清晰您会注意到从那以后它已被大量编辑看起来它使用 ES6,我认为在 2013 年这个问题被广泛提出时还没有。
2021-03-25 09:22:29
这很漂亮 - 而且,下划线对我来说比 jQuery 更必要。
2021-03-30 09:22:29
为什么这个选项会比选择的答案更好?
2021-04-04 09:22:29

使用lodash/underscore和的最短方法es6

_.zip(...matrix)

matrix可能在哪里

const matrix = [[1,2,3], [1,2,3], [1,2,3]];
我的天哪,这是一个简短的解决方案。刚刚了解了...运算符 - 用它来将一个字符串分解成一个字母数组...感谢您的回复
2021-03-18 09:22:29
或者,没有 ES6: _.zip.apply(_, matrix)
2021-03-27 09:22:29
你能扩展一下吗?我不明白你在这里说什么。那个短片应该可以解决问题?或者它只是一部分还是什么?
2021-03-29 09:22:29
关闭但 _.unzip(matrix) 更短;)
2021-04-02 09:22:29