Creating multidimensional arrays and matrices in Javascript

An attempt to create a function mCreate()that specified a set of numbers returns a multidimensional array (matrix):

mCreate(2, 2, 2)    
//   [[[0, 0], [0, 0]], [[0, 0], [0, 0]]]

When these functions process only 2 levels of depth, i.e.: mCreate(2, 2) //[[0, 0], [0, 0]]I know, to make 2 levels, you can use 2 nested ones for loops, but the problem I am facing is how to handle the nth number of arguments.

Would this problem be better with recursion, otherwise how can I dynamically determine the number of nested for loopsthat I need, given the number of arguments?

ps: the most efficient way would be great, but not essential

RE-EDIT . After using Benchmark.js to test perf, the results were as follows:

BenLesh x 82,043 ops/sec ±2.56% (83 runs sampled)
Phil-P x 205,852 ops/sec ±2.01% (81 runs sampled)
Brian x 252,508 ops/sec ±1.17% (89 runs sampled)
Rick-H x 287,988 ops/sec ±1.25% (82 runs sampled)
Rodney-R x 97,930 ops/sec ±1.67% (81 runs sampled)
Fastest is Rick-H

@briancavalier JSbin:

const mCreate = (...sizes) => (initialValue) => _mCreate(sizes, initialValue, sizes.length-1, 0)

const _mCreate = (sizes, initialValue, len, index) =>
    Array.from({ length: sizes[index] }, () => 
        index === len ? initialValue : _mCreate(sizes, initialValue, len, index+1))
mCreate(2, 2, 2)(0)
+4
5

- ( ES2015):

const mCreate = (...sizes) => 
    Array.from({ length: sizes[0] }, () => 
        sizes.length === 1 ? 0 : mCreate(...sizes.slice(1)));

JS Bin

EDIT: , :

const mCreate = (...sizes) => (initialValue) => 
    Array.from({ length: sizes[0] }, () => 
        sizes.length === 1 ? initialValue : mCreate(...sizes.slice(1))(initialValue));

:

mCreate(2, 2, 2)('hi'); 
// [[["hi", "hi"], ["hi", "hi"]], [["hi", "hi"], ["hi", "hi"]]]

JSBin

+7

:

function mCreate() {
  var result = 0, i;

  for(i = arguments.length - 1; i >= 0 ; i--) {
    result = new Array(arguments[i]).fill(result);
  }

  return JSON.parse(JSON.stringify(result));
}

JSON , .

function mCreate() {
  var result = 0, i;
  
  for(i = arguments.length - 1; i >= 0 ; i--) {
    result = new Array(arguments[i]).fill(result);
  }

  return JSON.parse(JSON.stringify(result));
}


console.log(JSON.stringify(mCreate(2, 2, 2)));
console.log(JSON.stringify(mCreate(1, 2, 3, 4)));
console.log(JSON.stringify(mCreate(5)));
console.log(JSON.stringify(mCreate(1, 5)));
console.log(JSON.stringify(mCreate(5, 1)));

var m = mCreate(1, 2, 3, 4);
m[0][1][1][3] = 4;
console.log(JSON.stringify(m));
Hide result
+4

, . .

:

  • 0 -value

, :

function nested() {
  // handle the deepest level first, because we need to generate the zeros
  var result = [];
  for (var zeros = arguments[arguments.length - 1]; zeros > 0; zeros--) {
    result.push(0);
  }

  // for every argument, walking backwards, we clone the
  // previous result as often as requested by that argument
  for (var i = arguments.length - 2; i >= 0; i--) {
    var _clone = [];
    for (var clones = arguments[i]; clones > 0; clones--) {
      // result.slice() returns a shallow copy
      _clone.push(result.slice(0));
    }

    result = _clone;
  }

  if (arguments.length > 2) {
    // the shallowly copying the array works fine for 2 dimensions,
    // but for higher dimensions, we need to compensate
    return JSON.parse(JSON.stringify(result));
  }

  return result;
}

- , , . gazillion (, mocha AVA). ( ), :

var tests = [
  {
    // the arguments we want to pass to the function.
    // translates to nested(2, 2)
    input: [2, 2],
    // the result we expect the function to return for
    // the given input
    output: [
      [0, 0],
      [0, 0]
    ]
  },
  {
    input: [2, 3],
    output: [
      [0, 0, 0],
      [0, 0, 0]
    ]
  },
  {
    input: [3, 2],
    output: [
      [0, 0],
      [0, 0],
      [0, 0]
    ]
  },
  {
    input: [3, 2, 1],
    output: [
      [
        [0], [0]
      ],
      [
        [0], [0]
      ],
      [
        [0], [0]
      ]
    ]
  },
];

tests.forEach(function(test) {
  // execute the function with the input array as arguments
  var result = nested.apply(null, test.input);
  // verify the result is correct
  var matches = JSON.stringify(result) === JSON.stringify(test.output);
  if (!matches) {
    console.error('failed input', test.input);
    console.log('got', result, 'but expected', rest.output);
  } else {
    console.info('passed', test.input);
  }
});

, , nested(3, 0), nested(0, 4), nested(3, -1) nested(-1, 2).

+2

@Pranav, arguments.

+

function mCreate() {
  var args = arguments;
  var result = [];
  if (args.length > 1) {
    for (var i = 1; i < args.length; i++) {
      var new_args = Array.prototype.slice.call(args, 1);
      result.push(mCreate.apply(this, new_args));
    }
  } else {
    for (var i = 0; i < args[0]; i++) {
      result.push(0)
    }
  }
  return result;
}

function print(obj) {
  document.write("<pre>" + JSON.stringify(obj, 0, 4) + "</pre>");
}
print(mCreate(2, 2, 2, 2))
Hide result
0

The bottom line is to pass the result createas the second argument create, with the exception of the last (or the first, depending on how you look at it):

function create(n, v) {
  let arr = Array(n || 0);
  if (v !== undefined) arr.fill(v);
  return arr;
}

create(2, create(2, 0)); // [[0,0],[0,0]]
create(2, create(2, create(2, 0))); // [[[0,0],[0,0]],[[0,0],[0,0]]]

Demo

Using a loop, we can build the dimensions of the array:

function loop(d, l) {
  var out = create(d, 0);
  for (var i = 0; i < l - 1; i++) {
    out = create(d, out);
  }
  return out;
}

loop(2,2) // [[0,0],[0,0]]
loop(2,3) // [[[0,0],[0,0]],[[0,0],[0,0]]]
loop(1,3) // [[[0]]]

Demo

0
source

All Articles