4

My goal is transpose a matrix; however, the sub-arrays do not all have equal length. For example: [[1,2,3], [4,5], [0,-1,0,0]]. I can't transpose this because the indices don't match up. What I need is:

[[1,2,3,undefined],
[4,5,undefined,undefined],
[0,-1,0,0]]

So that the shorter rows all match the same length as the longest row, but then are filled with undefined in the extended slots.

I'm well aware I can do this in ways that are probably considered slower or more crude, namely by initializing and empty array and copying, or concating arrays of undefined. Does javascript have some sort of native way of doing this? I took a look at fill, but it doesn't seem like what I need.

4
  • All arrays will have length 4? Commented Apr 1, 2016 at 17:03
  • Do you know the max length beforehand, or do you need to search the nested arrays for the max length first? Also, I'm not convinced undefined is the right thing to add. Commented Apr 1, 2016 at 17:04
  • @Andy Yeah, I need to determine the max length first. I don't know it in advance. Commented Apr 1, 2016 at 17:06
  • You are jumping from the notion of transposing a ragged array to needing to fill out the rows, There are ways of tranposing that would not require that. Commented Apr 1, 2016 at 18:35

3 Answers 3

2

Try to use the length property of array,

var arr = [[1,2,3], [4,5], [0,-1,0,0]];
//getting the max length among the sub arrays.
var max = arr.reduce(function(a,b){ return Math.max(a, b.length) }, 0);
//setting the max length to all the sub arrays.
arr = arr.map(function(itm){ return (itm.length = max, itm) });

console.log(arr[0]); //[1, 2, 3, undefined × 1]
console.log(arr[1]); //[4, 5, undefined × 2]
console.log(arr[2]); //[0, -1, 0, 0]

Ok here is a normal version of the above code,

var arr = [
  [1, 2, 3],
  [4, 5],
  [0, -1, 0, 0]
];

//getting the max length among the sub arrays.
var max = arr.reduce(function(a, b) {
  return Math.max(a, b.length)
}, 0);

//setting the max length to all the sub arrays.
arr = arr.map(function(itm) {
  itm.length = max;
  return itm
});

console.log(arr[0]); //[1, 2, 3, undefined × 1]
console.log(arr[1]); //[4, 5, undefined × 2]
console.log(arr[2]); //[0, -1, 0, 0]

And here is a plain old for loop method for your clear understanding,

var arr = [[1, 2, 3],[4, 5],[0, -1, 0, 0]];
var max = 0;

for(var i=0;i<arr.length;i++) {
 max = Math.max(max, arr[i].length);
}
for(var i=0;i<arr.length;i++) {
 arr[i].length = max
}

console.log(arr[0]); //[1, 2, 3, undefined × 1]
console.log(arr[1]); //[4, 5, undefined × 2]
console.log(arr[2]); //[0, -1, 0, 0]

DEMO

Sign up to request clarification or add additional context in comments.

12 Comments

Can you explain the syntax for (itm.length = max, itm). What is going on here?
@AlanH That means itm.length = max; return itm; It's a shorthand. I used comma operator there. It will be handy at situations like this.
Sorry, I still don't understand, can you write it out without shorthand?
@AlanH jsfiddle.net/gop7fueu Have a look at here. Also read about map and reduce.
@RajaprabhuAravindasamy, it is bad style, because it has no functionality in this case. please have a look for some usfull cases comma operator
|
2

Array.reduce function is a good stuff. But Array.forEach will go faster in this case. Besides, array length is dynamic property, no need to use Array.map:

var arr = [[1,2,3], [4,5], [0,-1,0,0]],
    max = 0;

arr.forEach(function(v){ if (v.length > max) max = v.length; });
arr.forEach(function(v){ v.length = max; });

2 Comments

This is how I personally would do it. The use of reduce() is clever but I think it overcomplicates this particular task.
@RickHitchcock, yes. We, developers, sometimes doing simple things in a complicated way )
1

A version with this. Now with real undefined, not with sparse holes.

var arr = [[1, 2, 3], [4, 5], [0, -1, 0, 0]];

arr.forEach(function (item) {
    var i = item.length;
    while (i < this) {
        item[i++] = undefined;
    }
}, arr.reduce(function (a, b) {
    return Math.max(a, b.length);
}, 0));

arr[1].forEach(function (a, i) {
    document.write(i + ': ' + a + '<br>');
});
document.write('<pre>' + JSON.stringify(arr, 0, 4) + '</pre>');

7 Comments

Are you sure that this code will be readable for your peers in future? :) It is just a simple task for OP. Do not complicate it.
I have already +1 ed for you. Because you made me look at the doc today for forEach's second argument. :)
That's horrible. Gives entirely new meaning to the term "obfuscation". In addition, it doesn't even do what the OP claims to have wanted, which was to fill out the rows with "real" undefineds; whether or not that is actually necessary is another issue.
@torazaburo, there are real undefined in the array, please see edit. JSON.stringify displays them as null.
Well, we're talking about angels dancing on the head of a pin. The OP, for what it's worth, said filled with undefined in the extended slots. If I say var a = [1]; a.length = 2;;, then a[1] is not "filled with undefined"; it's a hole, which when I access it is reported as undefined, but is different.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.