在JavaScript中转换2D数组

我有一个数组的数组,如下所示:

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

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

 array[0].map((col, i) => array.map(row => row[i])); 

map按顺序为数组中的每个元素调用一次提供的callback函数,并从结果中构造一个新的数组。 只对已经赋值的数组的索引调用callback 。 对于已被删除或从未被赋值的索引,不会调用它。

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

你可以使用underscore.js

 _.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]]) 

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

 transpose = m => m[0].map((x,i) => m.map(x => x[i])) 

最短的方式与lodash / underscorees6

 _.zip(...matrix) 

matrix可以是:

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

你只要做一遍就可以在原地进行:

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

只是另一个使用Array.map变体。 使用索引允许将M != Nmatrix转置:

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

所有的转置都是先将元素列映射,然后再逐行。

如果你有使用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]] 
 <script src="ajax/libs/ramda/0.22.1/ramda.min.js"></script> 

整洁纯洁:

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

如果提供空arrays,以前的解决scheme可能会导致失败。

这里是作为一个函数:

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

更新。 用扩展运算符可以写得更好:

 const transpose = matrix => matrix.reduce(($, row) => row.map((_, i) => [...($[i] || []), row[i]]), [] ) 

编辑:这个答案不会转置的matrix,但旋转它。 第一,我没有仔细阅读这个问题:D

顺时针和逆时针旋转:

  function rotateCounterClockwise(a){ var n=a.length; for (var i=0; i<n/2; i++) { for (var j=i; j<ni-1; j++) { var tmp=a[i][j]; a[i][j]=a[j][ni-1]; a[j][ni-1]=a[ni-1][nj-1]; a[ni-1][nj-1]=a[nj-1][i]; a[nj-1][i]=tmp; } } return a; } function rotateClockwise(a) { var n=a.length; for (var i=0; i<n/2; i++) { for (var j=i; j<ni-1; j++) { var tmp=a[i][j]; a[i][j]=a[nj-1][i]; a[nj-1][i]=a[ni-1][nj-1]; a[ni-1][nj-1]=a[j][ni-1]; a[j][ni-1]=tmp; } } return a; } 

您可以通过使用以下内容来实现无循环。

  • Array
  • Array.prototype.map
  • Array.prototype.reduce
  • Array.prototype.join
  • String.prototype.split

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

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

这是一个演示我扔在一起。 注意缺less循环:-)

 // 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> 

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

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

function方法与减less安德鲁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]]) } 

香草的方法

 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启发的香草就地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]]; } } } 
 function invertArray(array,arrayWidth,arrayHeight) { var newArray = []; for (x=0;x<arrayWidth;x++) { newArray[x] = []; for (y=0;y<arrayHeight;y++) { newArray[x][y] = array[y][x]; } } return newArray; } 

ES6 1liners为:

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

我发现上面的答案要么难以阅读,要么太冗长,所以我自己写了一个答案。 我认为这是在线性代数中实现转置最直观的方法,您不要进行值交换 ,而是将每个元素插入到新matrix的正确位置:

 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 }