What would be the most elegant way to turn any array of (equal length) rows into an array of columns?
Eg:
[1,2,3]
[4,5,6]
# To
[1,4]
[2,5]
[3,6]
This is what I have so far:
grid = [
[1,2,3]
[4,5,6]
]
grid2 = []
for i in grid[0]
grid2.push []
for row, y in grid
for el, x in row
grid2[x].push el
Is there maybe even a 1-liner that would do it?
What would be the most elegant way to turn any array of (equal length) rows into an array of columns?
Eg:
[1,2,3]
[4,5,6]
# To
[1,4]
[2,5]
[3,6]
This is what I have so far:
grid = [
[1,2,3]
[4,5,6]
]
grid2 = []
for i in grid[0]
grid2.push []
for row, y in grid
for el, x in row
grid2[x].push el
Is there maybe even a 1-liner that would do it?
Share Improve this question edited May 11, 2011 at 22:46 Acorn asked May 11, 2011 at 22:37 AcornAcorn 50.6k30 gold badges140 silver badges178 bronze badges 2- It would probably help to specify in the question what language you're looking for - Javascript or Coffeescript? – nrabinowitz Commented May 11, 2011 at 23:10
- Either is fine really, as a concise solution in Javascript can be translated into an even more concise Coffeescript solution :) – Acorn Commented May 11, 2011 at 23:13
4 Answers
Reset to default 7In Javascript, if you are working in an environment with ECMAScript 5 array methods, the map()
function works nicely for this:
var grid2 = grid[0].map(function(col, i) {
return grid.map(function(row) {
return row[i];
});
});
This could be a one-liner if you killed the line breaks. :)
CoffeeScript:
grid[0].map (col, i) -> grid.map (row) -> row[i]
Don't use for..in with arrays where order is important!!
Using for..in with arrays has the following dangers:
All enumerable properties of the array will be returned, including those on Array.prototype and the array itself so either you must be absolutely confident that no such extensions have occurred, or you must do hasOwnProperty and numeric index checks
The order in which keys are returned is not guaranteed and can easily be disturbed - IE returns them in the order they are added, so if they are added out of order (e.g. using a decrementing while loop, which is quite mon) they will returned in reverse order
Try the following in Firefox and IE:
var a = [0,1,2,3];
var b = [];
var i = a.length;
while (i--) {
b[i] = a[i];
}
var s = [];
for (var p in b) {
s.push(b[p]);
}
alert(b + '\n' + s);
// Firefox: 0,1,2,3
// 0,1,2,3
// IE: 0,1,2,3
// 3,2,1,0
Where order is important, only use loops where you explicitly access keys in the order you require. This also applies to objects, since in javascript the order in which properties are returned using for..in for all objects is implementation dependent and varies across browsers (noting that in javascript, everything is an object).
For..in is OK to use with arrays where the above issues are either not important or are dealt with. It is a handy tool for sparse arrays and accessing non-numeric enumerable properties.
A generic transpose function is:
function rows2cols(a) {
var r = [];
var t;
for (var i=0, iLen=a.length; i<iLen; i++) {
t = a[i];
for (var j=0, jLen=t.length; j<jLen; j++) {
if (!r[j]) {
r[j] = [];
}
r[j][i] = t[j];
}
}
return r;
}
It can be shortened and optimisied, but the above is a reasonably performant and easily maintained function.
Try this:
var new_grid = [];
for(var i = 0; i < grid[0].length; i++){
new_grid.push([grid[0][i], grid[1][i]]);
// this is all under assumption that all the arrays are the same size
}
Would get you a result of:
new_grid = [
[1,4],
[2,5],
[3,6],
]
CoffeeScript:
((row[i] for row in grid) for i in [0...grid[0].length])