Transposing a 2D-array in JavaScript

JavascriptArraysMatrixTranspose

Javascript Problem Overview


I've got an array of arrays, something like:

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

I would like to transpose it to get the following array:

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

It's not difficult to programmatically do so using loops:

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

This, however, seems bulky, and I feel like there should be an easier way to do it. Is there?

Javascript Solutions


Solution 1 - Javascript

output = array[0].map((_, colIndex) => array.map(row => row[colIndex]));

>map calls a provided callback function once for each element in an array, in order, and constructs a new array from the results. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.

>callback is invoked with three arguments: the value of the element, the index of the element, and the Array object being traversed. [source]

Solution 2 - Javascript

Many good answers here! I consolidated them into one answer and updated some of the code for a more modern syntax:

One-liners inspired by Fawad Ghafoor and Ó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]));
}

Functional approach style with reduce by Andrew Tatomyr

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

Lodash/Underscore by 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]])
}

Even simpler Lodash/Underscore solution by Vigrant

_.unzip(matrix);

Vanilla approach

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

Vanilla in-place ES6 approach inspired by 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]];
    }
  }
}

Solution 3 - Javascript

here is my implementation in modern browser (without dependency):

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

Solution 4 - Javascript

You could use underscore.js

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

Solution 5 - Javascript

shortest way with lodash/underscore and es6:

_.zip(...matrix)

where matrix could be:

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

Solution 6 - Javascript

Neat and pure:

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

Previous solutions may lead to failure in case an empty array is provided.

Here it is as a function:

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

Update. It can be written even better with spread operator:

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

Solution 7 - Javascript

You can do it in in-place by doing only one pass:

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

Solution 8 - Javascript

Just another variation using Array.map. Using indexes allows to transpose matrices where 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]; 
    }); 
});

All there is to transposing is mapping the elements column-first, and then by row.

Solution 9 - Javascript

Another approach by iterating the array from outside to inside and reduce the matrix by mapping inner values.

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

Solution 10 - Javascript

If you have an option of using Ramda JS and ES6 syntax, then here's another way to do it:

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="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>

Solution 11 - Javascript

If using RamdaJS is an option, this can be achieved in one line: R.transpose(myArray)

Solution 12 - Javascript

Spread syntax should not be used as an alternative to push, it should only be used when you don't want to mutate the existing array.

Algorithm: For every column, just check if for that column there's a row in the resultant matrix, if there's already a row then simply push the element, else create a new row array and then push.

So, unlike many other solutions above, this solution doesn't create new arrays again and again, instead pushes onto the same array.

Also, take some time to appreciate the use of the Nullish Coalescing Operator.

const 
  transpose = arr => arr.reduce((m, r) => (r.forEach((v, i) => (m[i] ??= [], m[i].push(v))), m), []),
  matrix = [[1, 2, 3], [1, 2, 3], [1, 2, 3]]

console.log(transpose(matrix))

Solution 13 - Javascript

You can achieve this without loops by using the following.

It looks very elegant and it does not require any dependencies such as jQuery of 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)}

Here is a demo I threw together. Notice the lack of loops :-)

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

Solution 14 - Javascript

ES6 1liners as :

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

so same as Óscar's, but as would you rather rotate it clockwise :

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

let a = [
	[1,1,1]
	, ["_","_","1"]
]
let b = rotate(a);
let c = rotate(b);
let d = rotate(c);
console.log(`a ${a.join("\na ")}`);
console.log(`b ${b.join("\nb ")}`);
console.log(`c ${c.join("\nc ")}`);
console.log(`d ${d.join("\nd ")}`);

Yields

a 1,1,1 
a _,_,1

b _,1
b _,1
b 1,1 

c 1,_,_
c 1,1,1

d 1,1
d 1,_
d 1,_

Solution 15 - Javascript

Edit: This answer would not transpose the matrix, but rotate it. I didn't read the question carefully in the first place :D

clockwise and counterclockwise rotation:

	function rotateCounterClockwise(a){
		var n=a.length;
		for (var i=0; i<n/2; i++) {
			for (var j=i; j<n-i-1; j++) {
				var tmp=a[i][j];
				a[i][j]=a[j][n-i-1];
				a[j][n-i-1]=a[n-i-1][n-j-1];
				a[n-i-1][n-j-1]=a[n-j-1][i];
				a[n-j-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<n-i-1; j++) {
				var tmp=a[i][j];
				a[i][j]=a[n-j-1][i];
				a[n-j-1][i]=a[n-i-1][n-j-1];
				a[n-i-1][n-j-1]=a[j][n-i-1];
				a[j][n-i-1]=tmp;
			}
		}
        return a;
	}

Solution 16 - Javascript

I found the above answers either hard to read or too verbose, so I write one myself. And I think this is most intuitive way to implement transpose in linear algebra, you don't do value exchange, but just insert each element into the right place in the new 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
}

Solution 17 - Javascript

const transpose = array => array[0].map((r, i) => array.map(c => c[i])); console.log(transpose([[2, 3, 4], [5, 6, 7]]));

Solution 18 - Javascript

I think this is slightly more readable. It uses Array.from and logic is identical to using nested loops:

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

If you are dealing with arrays of unequal length you need to replace arr[0].length with something else:

var arr = [
  [1, 2],
  [1, 2, 3],
  [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.reduce(function(max, item) { return item.length > max ? item.length : max; }, 0) }, function(x, row) {
  return Array.from({ length: arr.length }, function(x, col) {
    return arr[col][row];
  });
});

console.log(result);

Solution 19 - Javascript

Since nobody so far mentioned a functional recursive approach here is my take. An adaptation of Haskell's Data.List.transpose.

var transpose = as => as.length ? as[0].length ? [as.reduce((rs, a) => a.length ? (rs.push(a[0]), rs) :
    rs, []
  ), ...transpose(as.map(a => a.slice(1)))] :
  transpose(as.slice(1)) :
  [],
  mtx = [
    [1],
    [1, 2],
    [1, 2, 3]
  ];

console.log(transpose(mtx))

.as-console-wrapper {
  max-height: 100% !important
}

Solution 20 - Javascript

Adding TS version here.

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

Solution 21 - Javascript

One-liner that does not change given array.

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

Solution 22 - Javascript

I didn't find an answer that satisfied me, so I wrote one myself, I think it is easy to understand and implement and suitable for all situations.

    transposeArray: function (mat) {
        let newMat = [];
        for (let j = 0; j < mat[0].length; j++) {  // j are columns
            let temp = [];
            for (let i = 0; i < mat.length; i++) {  // i are rows
                temp.push(mat[i][j]);  // so temp will be the j(th) column in mat
            }
            newMat.push(temp);  // then just push every column in newMat
        }
        return newMat;
    }

Solution 23 - Javascript

This one, is not only a super efficient one, but a pretty short solution.

Algorithm Time Complexity: O(n log n)

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

matrix.every((r, i, a) => (
   r.every((_, j) => (
      j = a.length-j-1,
      [ r[j], a[j][i] ] = [ a[j][i], r[j] ],
      i < j-1
   )), 
   i < length-2
));

console.log(matrix);
/*
Prints:
[
   [1,2,3,4],
   [1,2,3,4],
   [1,2,3,4],
   [1,2,3,4]
]
*/

The example above will do only 6 iterations.
For bigger matrix, say 100x100 it will do 4,900 iterations, this is 51% faster than any other solution provided here.

The principle is simple, you on only iterate through the upper diagonal half of the matrix, because the diagonal line never changes and the bottom diagonal half being is switched together with the upper one, so there is no reason to iterate through it as well. This way, you save a lot of running time, especially in a large matrix.

Solution 24 - Javascript

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

Solution 25 - Javascript

reverseValues(values) {
        let maxLength = values.reduce((acc, val) => Math.max(val.length, acc), 0);
        return [...Array(maxLength)].map((val, index) => values.map((v) => v[index]));
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionckerschView Question on Stackoverflow
Solution 1 - JavascriptFawad GhafoorView Answer on Stackoverflow
Solution 2 - JavascriptYangshun TayView Answer on Stackoverflow
Solution 3 - JavascriptMahdi JadalihaView Answer on Stackoverflow
Solution 4 - JavascriptJoeView Answer on Stackoverflow
Solution 5 - JavascriptmarcelView Answer on Stackoverflow
Solution 6 - JavascriptAndrew TatomyrView Answer on Stackoverflow
Solution 7 - Javascriptuser2422457View Answer on Stackoverflow
Solution 8 - JavascriptÓscar Gómez AlcañizView Answer on Stackoverflow
Solution 9 - JavascriptNina ScholzView Answer on Stackoverflow
Solution 10 - JavascriptKevin Le - KhnleView Answer on Stackoverflow
Solution 11 - JavascriptRafael RozonView Answer on Stackoverflow
Solution 12 - JavascriptAnonymous PandaView Answer on Stackoverflow
Solution 13 - JavascriptMr. PolywhirlView Answer on Stackoverflow
Solution 14 - JavascriptysleView Answer on Stackoverflow
Solution 15 - JavascriptAryan FirouzianView Answer on Stackoverflow
Solution 16 - JavascriptChangView Answer on Stackoverflow
Solution 17 - JavascriptpankView Answer on Stackoverflow
Solution 18 - JavascriptSalman AView Answer on Stackoverflow
Solution 19 - JavascriptReduView Answer on Stackoverflow
Solution 20 - JavascriptKarl AdlerView Answer on Stackoverflow
Solution 21 - JavascriptOffpicsView Answer on Stackoverflow
Solution 22 - JavascriptChuan SunView Answer on Stackoverflow
Solution 23 - JavascriptSlavik MeltserView Answer on Stackoverflow
Solution 24 - JavascriptSamuel ReidView Answer on Stackoverflow
Solution 25 - JavascriptOndrej MachalaView Answer on Stackoverflow