0

I want to create an array matrix like this:

createMatrix(4);

// logs:
[[0,0,0,0],
 [0,0,0,0],
 [0,0,0,0],
 [0,0,0,0]];

Currently my solution is :

function createMatrix (n) {
  var innerArr;
  var outerArr = [];

  for (var i=0; i<n; i++){
    innerArr = [];
    for (var j=0; j<n; j++) {
      innerArr.push(0);
    }
    outerArr.push(innerArr);
  }
}

console.log(outerArr);

Is there a more efficient way to do this? This will iterate nxn times which is very inefficient for something very simple.

jmancherje
  • 6,439
  • 8
  • 36
  • 56

2 Answers2

2

With the ECMAScript 2015 function Array.prototype.fill():

Array(row_count).fill(Array(column_count).fill(0)).map(a => a.slice())

Explanation:

// a sparse array with row_count "absent" items:
Array(row_count)
// an array with column_count members with the value 0:
                      Array(column_count).fill(0)
// an array with row_count times the identic array as value:
Array(row_count).fill(Array(column_count).fill(0))
// shallow copy the inner array:
Array(row_count).fill(Array(column_count).fill(0)).map(a => a.slice())

Speed?

Seemingly the Array.prototype.fill() variant gets faster as the matrix grows (in relation to the loops). At least in Firefox. YMMV.

Kijewski
  • 25,517
  • 12
  • 101
  • 143
2

There are a couple of approaches you could take:

concat()/slice()

var numCols = 4;
var numRows = 4;

var innerArrSrc = [];
var outerArr = [];

for (var i = 0; i < numCols; i++) {
    innerArrSrc.push(0);
}

for (var j = 0; j < numRows; j++) {
    outerArr.push(innerArrSrc.concat()); // Could also use innerArrSrc.slice();
}

Both Array.prototype.concat() and Array.prototype.slice() will return a shallow copy of the source array.

one-dimensional array

Alternatively, you could represent your matrix as an one-dimensional array rather than a multi-dimensional one and provide functions to access specific indexes based on row-column values:

var numRows = 4;
var numCols = 4;
var len = numRows * numCols;

var outerArr = [];

for (var i = 0; i < len; i++) {
    outerArr.push(0);
}

A function to access a specific index of a matrix represented this way might look like:

function getMatrixIndex(myMatrix, col, row, numCols) {

    var index = row * numCols + col;
    return myMatrix[index];
}

Array.prototype.fill

If you want to take advantage of new ES6 features Array.prototype.fill should suit your needs:

// Multi-dimensional
var numRows = 4;
var numCols = 4;

var outerArr = new Array(row_count).fill(new Array(column_count).fill(0)).map(a => a.slice());

// Or one-dimensional
var len = numRows * numCols;
var oneDim = new Array(row_count * column_count).fill(0);

jsPerf tests

You can run this jsPerf test to see which is fastest. I've tested in:

  • Firefox 42.0 32-bit on Windows NT 10.0 64-bit
  • Chrome 44.0.2403.130 32-bit on Windows NT 10.0 64-bit
  • Chrome 47.0.2526.73 32-bit on Windows NT 10.0 64-bit
  • Android Browser 42.0 (Gecko) on Android 6.0
NoobsArePeople2
  • 1,986
  • 14
  • 21
  • For `Array` you don't need the `new` keyword. It's a little easier to read, in my opinion. For the `Array.prototype.fill` variant you'll have `numRows` times the same array. See my answer. +1 for the 1-D array solution! – Kijewski Dec 03 '15 at 01:30
  • True, but I the question was edited slightly while I was writing my answer ;) I want to dig into @Kay's comment first and then edit my answer to better fit the updated question. – NoobsArePeople2 Dec 03 '15 at 05:08
  • @Kay good catch on my `Array.prototype.fill` bug. I've fixed it and updated the jsPerf test as well. – NoobsArePeople2 Dec 03 '15 at 17:59