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.

asked Sep 18, 2017 at 22:16
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);

answered Sep 18, 2017 at 22:20
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);

answered Sep 18, 2017 at 22:31

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);
answered Sep 18, 2017 at 22:41

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);
    
answered Sep 18, 2017 at 23:13

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) 
}, [])
answered May 8, 2020 at 14:52

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.