Search code examples
recursionmultidimensional-arraynested-loops

How to reshape a flattened array to a multidimensional array in arbitray shape in Javascript?


[what I have]

An flattened, or 1-dimentional, array with n elements, e.g. the array A with 12 items below.

const A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 

[what i want to do]

Reshape A to a multidimensional array B whose shape is determined by array C which may vary depending on other conditions.

// scenario 1 
const C = [ 2, 3, 2 ] 
// reshaped A should be: 
// [[[1, 2], 
//   [3, 4],  
//   [5, 6]],
//  [[7, 8], 
//   [9, 10], 
//   [11, 12]]]

// scenario 2
const C = [ 3, 4 ]
// reshaped A should be: 
// [[1, 2, 3, 4], 
//  [5, 6, 7, 8], 
//  [9, 10, 11, 12]]

// and so on... 

[what I have tried]

I found the follolwing reference which can unflattend a flattened array to a 2-dimensional array by arbitray number of rows: Unflatten Arrays into groups of fours [closed]

function arrayUnflatten (_flattenedArray, _numRows) {
    const len = _flattenedArray.length;
    const unflattenedArray = []; 
    while (_flattenedArray.length > 0) unflattenedArray.push(_flattenedArray.splice(0, _numRows));
    return unflattenedArray; 
}

[what I haven't figured out]

I haven't figured out how to make a "dynamically nested for loop", or some kind of recursion is needed, to reshape the 1-D array to a multidimensional arry in arbitrary shape determied by another array.

Help is appreciated.


Solution

  • Here's my solution:


    const A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
    const C = [3, 4];
    
    function unflattenArray(arr, dim) {
      let elemIndex = 0;
    
      if (!dim || !arr) return [];
    
      function _nest(dimIndex) {
        let result = [];
    
        if (dimIndex === dim.length - 1) {
          result = result.concat(arr.slice(elemIndex, elemIndex + dim[dimIndex]));
          elemIndex += dim[dimIndex];
        } else {
          for (let i = 0; i < dim[dimIndex]; i++) {
            result.push(_nest(dimIndex + 1));
          }
        }
    
        return result;
      }
      return _nest(0);
    }
    
    console.log(unflattenArray(A, C));


    _nest is a recursive function. Because of closure it can access elemIndex, arr and dim. elemIndex refers to the index of the current element being read from array arr.

    _nest takes the index of the current dimension: dimIndex. It's first called with 0.

    • If dimIndex refers to the last dimension in dim array, then a 1D array of the corresponding size has to be returned. This is the base condition of recursion. It returns a slice of arr starting at elemIndex, of size dim[dimIndex].
    • Else it makes a call to _nest with the next dimension, dim[dimIndex] times. For e.g when dimIndex is 0 i.e size is 3 => we need 3 arrays hence we call _nest thrice with the size of each array which is 4 in the above example.