36

For instance I have a matrix like this:

|1 2 3|    
|4 5 6|
|7 8 9|

and I need it to convert into a matrix like this:

|1 4 7|    
|2 5 8|
|3 6 9|

What is the best and optimal way to achieve this goal?

caub
  • 2,709
  • 2
  • 28
  • 31
Bakhtiyor
  • 7,198
  • 15
  • 55
  • 77

5 Answers5

80

DuckDucking turned up this by Ken. Surprisingly, it's even more concise and complete than Nikita's answer. It retrieves column and row lengths implicitly within the guts of map().

function transpose(a) {
    return Object.keys(a[0]).map(function(c) {
        return a.map(function(r) { return r[c]; });
    });
}

console.log(transpose([
    [1,2,3],
    [4,5,6],
    [7,8,9]
]));

[[1,4,5],[2,5,8],[7,8,9]

hobs
  • 18,473
  • 10
  • 83
  • 106
  • 4
    Object.keys isnt supported by IEX<9 so in that case i'd stick to one of the other answers if you need to provide support for that. – Joris Kroos May 31 '13 at 09:58
  • Good point. Hadn't noticed that. Thanks for the tip. – hobs May 31 '13 at 20:31
  • 3
    though there is a fix for that detailed here... https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys – Tom P Jun 11 '13 at 16:30
  • @hobs can you explain what `a[0]` is? – TheRealFakeNews Mar 31 '16 at 18:50
  • @AlanH it's the first inner array in your array of arrays. This inner array is the first row of your 2D array (matrix) if you stored your data in [row-major order](https://en.wikipedia.org/wiki/Row-major_order). [The docs](http://www.w3schools.com/jsref/jsref_obj_array.asp) and other [SO answers](http://stackoverflow.com/a/15995788/623735) give more detail. – hobs Apr 03 '16 at 00:47
22

See article: Transpose An Array In JavaScript and jQuery

function transpose(a) {

  // Calculate the width and height of the Array
  var w = a.length || 0;
  var h = a[0] instanceof Array ? a[0].length : 0;

  // In case it is a zero matrix, no transpose routine needed.
  if(h === 0 || w === 0) { return []; }

  /**
   * @var {Number} i Counter
   * @var {Number} j Counter
   * @var {Array} t Transposed data is stored in this array.
   */
  var i, j, t = [];

  // Loop through every item in the outer array (height)
  for(i=0; i<h; i++) {

    // Insert a new row (array)
    t[i] = [];

    // Loop through every item per item in outer array (width)
    for(j=0; j<w; j++) {

      // Save transposed data.
      t[i][j] = a[j][i];
    }
  }

  return t;
}

console.log(transpose([[1,2,3],[4,5,6],[7,8,9]]));
Web_Designer
  • 72,308
  • 93
  • 206
  • 262
troynt
  • 1,900
  • 15
  • 21
  • Unfortunately, this approach adds a new element to each array in your application! Look here: http://jsfiddle.net/gj6q1k0j/ – vektor Aug 20 '14 at 15:18
  • @vektor your input should look like [[1,2,3,4]] Also, you should loop like `for (var key in p) { if (p.hasOwnProperty(key)) { ` If you plan on doing for..in But yes, it is probably a bad idea to extend Array. I'll change example. – troynt Aug 20 '14 at 22:42
  • Thanks for the updated example. My point was that the original solution broke all the Arrays... – vektor Aug 21 '14 at 08:35
7

Just like in any other language:

int[][] copy = new int[columns][rows];
for (int i = 0; i < rows; ++i) {
    for (int j = 0; j < columns; ++j) {
        copy[j][i] = original[i][j];
    }
}

You just have to construct the 2D array differently in JS. Like this:

function transpose(original) {
    var copy = [];
    for (var i = 0; i < original.length; ++i) {
        for (var j = 0; j < original[i].length; ++j) {
            // skip undefined values to preserve sparse array
            if (original[i][j] === undefined) continue;
            // create row if it doesn't exist yet
            if (copy[j] === undefined) copy[j] = [];
            // swap the x and y coords for the copy
            copy[j][i] = original[i][j];
        }
    }
    return copy;
}

console.log(transpose([
    [1,2,3],
    [4,5,6],
    [7,8,9]
]));
Web_Designer
  • 72,308
  • 93
  • 206
  • 262
Nikita Rybak
  • 67,365
  • 22
  • 157
  • 181
  • Unlike the other solution, this one works for jagged arrays i.e. if you change [4,5,6] to [4,5,6,0], this solution still works. Others don't. – aleemb Apr 08 '20 at 18:12
6

I don't have enough reputation to comment (wtf.), so I need to post Ken's updated version as a separate answer:

function transpose(a) {
    return a[0].map(function (_, c) { return a.map(function (r) { return r[c]; }); });
}
KIT-Inwi
  • 86
  • 1
  • 5
2

Compact version of Hobs' answer using arrow functions from ES6:

function transpose(matrix) {
    return Object.keys(matrix[0])
        .map(colNumber => matrix.map(rowNumber => rowNumber[colNumber]));
}
Community
  • 1
  • 1