Trasposizione di un array 2D in JavaScript

Ho una serie di array, qualcosa del tipo:

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

Vorrei trasporlo per ottenere il seguente array:

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

Non è difficile farlo a livello di programmazione utilizzando i loop:

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

Questo, tuttavia, sembra ingombrante, e sento che dovrebbe esserci un modo più semplice per farlo. È lì?

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

    map chiama una funzione di callback fornita una volta per ciascun elemento in una matrice, nell’ordine, e costruisce una nuova matrice dai risultati. callback è invocata solo per gli indici dell’array che hanno assegnato valori; non è invocato per gli indici che sono stati cancellati o che non sono mai stati assegnati valori.

    callback viene invocato con tre argomenti: il valore dell’elemento, l’indice dell’elemento e l’object Array che viene attraversato. [fonte]

    Potresti usare underscore.js

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

    ecco la mia implementazione nel browser moderno (senza dipendenza):

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

    modo più breve con lodash / underscore ed es6 :

     _.zip(...matrix) 

    dove la matrix potrebbe essere:

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

    Puoi farlo sul posto facendo solo un passaggio:

     function transpose(arr,arrLen) { for (var i = 0; i < arrLen; i++) { for (var j = 0; j  

    Pulito e puro:

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

    Le soluzioni precedenti potrebbero causare errori nel caso in cui venga fornita una matrice vuota.

    Qui è come una funzione:

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

    Aggiornare. Può essere scritto ancora meglio con l’operatore di spread:

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

    Solo un’altra variazione usando Array.map . L’utilizzo degli indici consente di trasporre matrici in cui 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]; }); }); 

    Tutto quello che c’è da trasporre è mappare la colonna degli elementi prima e poi per riga.

    Molte buone risposte qui! Li ho consolidati in una sola risposta e aggiornato parte del codice per una syntax più moderna:

    One-liner ispirati a Fawad Ghafoor e Ó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])); } 

    Stile di approccio funzionale con riduzione di Andrew Tatomyr

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

    Lodash / Underscore di marcel

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

    Approccio alla vaniglia

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

    Approccio ESB Vanilla sul posto ispirato da Emanuel Saringan

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

    Se hai la possibilità di utilizzare la syntax Ramda JS ed ES6, ecco un altro modo per farlo:

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

    Modifica: questa risposta non traspone la matrice, ma la ruota. Non ho letto attentamente la domanda in primo luogo: D

    rotazione oraria e antioraria:

      function rotateCounterClockwise(a){ var n=a.length; for (var i=0; i 

    Se l’utilizzo di RamdaJS è un’opzione, è ansible R.transpose(myArray) in un’unica riga: R.transpose(myArray)

    È ansible ottenere questo senza loop utilizzando il seguente.

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

    Sembra molto elegante e non richiede alcuna dipendenza come jQuery di 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); } 

    minified

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

    Ecco una demo che ho buttato insieme. Notare la mancanza di loop 🙂

     // 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(['
    '])); }
     #out { white-space: pre; } 
     

    ES6 1liner come:

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

    lo stesso di Óscar, ma come preferiresti ruotarlo in senso orario:

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

    Ho trovato le risposte sopra o difficili da leggere o troppo prolisse, quindi ne scrivo una anch’io. E penso che questo sia il modo più intuitivo per implementare la trasposizione in algebra lineare, non si fa scambio di valori , ma basta inserire ogni elemento nella giusta posizione nella nuova matrice:

     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 } 
     function invertArray(array,arrayWidth,arrayHeight) { var newArray = []; for (x=0;x 

    Penso che questo sia leggermente più leggibile. Utilizza Array.from e la logica è identica all’utilizzo di cicli nidificati:

     var arr = [ [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4] ]; /* * arr[0].length = 4 = number of result rows * arr.length = 3 = number of result cols */ var result = Array.from({ length: arr[0].length }, function(x, row) { return Array.from({ length: arr.length }, function(x, col) { return arr[col][row]; }); }); console.log(result);