1

Hello I would like to create in JavaScript multidimensional array like this:

var multiLayer = [
  ["First", "Second", 4],
  [5, 6, 3],
  [3, 2, 1]
];

From simple array like that

var simple = [
  "First",
  "Second",
  4,
  5,
  6,
  3,
  3,
  2,
  1
];

Here is my code yet

var multi = [];
var howMuchBreak = 3;

for (var i = 0; i < simple.length; i++) {
  multi.push(simple[i + howMuchBreak])
}

Variable howMuchBreak defines on which position in the index must be create next nested array.

1

5 Answers 5

4

You can use Array.slice(start, end) and increment the start by the desired sub-array length:

var simple = [
  "First",
  "Second",
  4,
  5,
  6,
  3,
  3,
  2,
  1
];
var multiLayer = [];
// sub array length, in your example 3
var l = 3;
for (var i=0; i<simple.length; i += l) {
  multiLayer.push(simple.slice(i, i+l));
}
console.log(multiLayer);

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

Comments

2

Another solution, using the remainder % operator. The other answer solves the problem in fewer lines (actually, the other answer does it in 18 i do it in 19) but i am adding this just to acquaint you with the % operator, very useful.

Quoting from MDN:

The remainder operator returns the remainder left over when one operand is divided by a second operand.

Ponder the code and try to find out why and how this operator fits your situation :)

var simple = [
  "First",
  "Second",
  4,
  5,
  6,
  3,
  3,
  2,
  1
];

var multi = [];
var sub_array_length = 3;
for (var i = 0; i < simple.length; i++) {
if(i % sub_array_length === 0) {	
multi[multi.length] = [];
}	
multi[multi.length - 1].push(simple[i]);
}

console.log(multi);

Comments

1

or using while...

var arr=[1,2,3,4,5,6,7,8,9,10]
var array = [], chunk = 3;

while (arr.length > 0){ array.push(arr.splice(0, chunk)); }

console.log(array);

6 Comments

Your answer is the shortest in terms of line-length (even after you multi-linify the array) :)
It should be noted that this doesn't preserve the original (one-dimensional) array.
@insert_name_here I would say that is negligible since it will provide the correct results when supplied with the original array.
However, I believe there is a small misunderstanding, the entire solution relies on the use of splice which isn't really what OP asked for (since it modifies the original array).
However, I believe there is a small misunderstanding, the entire solution relies on the use of splice which isn't really what OP asked for (since it modifies the original array).
|
0

I made three variations:

First - Adaptive limiter

What it does is, well, do what you want but adapt if there's space left.

Example:

  • Array: [1,2,3,4,5]
  • Break by: 2
  • Will generate: [ [1,2], [3,4], [5] ]

    var simple = [ "First", "Second", 4, 5, 6, 3, 3, 2, 1 ];

    var multi = [];
    var howMuchBreak = 2;
    var i = 0; // start counting simple array elements
    var x = 0; // start counting limited array elements
    
    while (i < simple.length) {
    
      var limitedArray = [];
      x = 0;
      while (x < howMuchBreak && i < simple.length) {
        limitedArray.push(simple[i]);
        x++;
        i++;
      }
    
      multi.push(limitedArray);
    
    }
    

Second - Non-adaptive limiter

Also does what you want but it doesn't adapt to extra space.

Example:

  • Array: [1,2,3,4,5]
  • Break by: 2
  • Will generate: [ [1,2], [3,4], [5, undefined] ]

    var simple = [ "First", "Second", 4, 5, 6, 3, 3, 2, 1 ];

    var multi = [];
    var howMuchBreak = 2;
    var i = 0; // start counting simple array elements
    var x = 0; // start counting limited array elements
    
    while (i < simple.length) {
    
      var limitedArray = [];
      x = 0;
      while (x < howMuchBreak) {
        limitedArray.push(simple[i]);
        x++;
        i++;
      }
    
      multi.push(limitedArray);
    
    }
    

Third - ES6 API-like

It does the same as the others above but with more elegance. Also, I wanted to introduce you to new features of javascript to improve your code.

That code uses a config JSON with two properties:

  • adaptive: <boolean> (defaults to true)
  • breakBy: <integer>

Simply pass the simple array first and then the config to the simpleToMulti function:

let multi = simpleToMulti( simpleArray, config );

Example 1:

  • Array: [1,2,3,4,5]
  • config: { adaptive: true, breakBy: 3 }
  • Will generate: [ [1,2,3], [4,5] ]

Example 2:

  • Array: [1,2,3,4,5]
  • config: { adaptive: false, breakBy: 2 }
  • Will generate: [ [1,2], [3,4], [5, undefined] ]

    let simple = ["First", "Second", 4, 5, 6, 3, 3, 2, 1];
    
    let config = {
      breakBy: 4,
      adaptive: true
    };
    
    function simpleToMulti(arr, config) {
    
      // normalize config
      if (config.breakBy === undefined) {
        console.warn('simpleToMulti: You must inform the breakBy config property');
        return;
      }
      config.adaptive = config.adaptive === undefined ? true : config.adaptive;
    
      // do the magic
      let limitedArray = [];
      let multiArray = [];
      arr.forEach( value => {
    
        if (limitedArray.length < config.breakBy) {
          limitedArray.push(value);
        }
    
        if (limitedArray.length === config.breakBy) {
          multiArray.push(limitedArray);
          limitedArray = [];
        }
    
      });
    
      if (limitedArray.length !== 0) {
        if (config.adaptive) {
          multiArray.push(limitedArray);
        } else {
          while (limitedArray.length < config.breakBy) {
            limitedArray.push(undefined);
          }
          multiArray.push(limitedArray);
        }
      }
    
      return multiArray;
    }
    
    
    let multi = simpleToMulti(simple, config);
    console.log(multi);
    

3 Comments

The non-adaptive version is not a feature, it is a bug (why would you want that behavior ?). Also, there is no need to use let if you aren't utilizing block-scoping; you should just stick with var for these cases (where the let will be bound to the global scope or the enclosing function`s scope).
Here is your example but with some modifications i made (if you are interested): jsfiddle.net/syxxuw13
Thanks! I got used to always using let and forgot that var also does the same if I'm already inside a function. Not exactly the same... but still ok for that case. I wouldn't say that the non-adaptive is a bug because maybe he really wants every array to have the same length, idk, it wasn't clear so I did it just to be sure. Thanks for taking the time to make the modifications! (:
0

I've been spending the last hour trying to find a way to create a multidimensional array from an array of ints. This is what I finally came up with (reduceRightand timesare from the lodash library).

let dimensions = [1, 2, 3]

_.reduceRight(dimensions, (result, dimension) => {
    return _.times(dimension, () => result)    
}, [])

Comments

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.