[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.
CodePudding user response:
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));
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
_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 indim
array, then a 1D array of the corresponding size has to be returned. This is the base condition of recursion. It returns a slice ofarr
starting atelemIndex
, of sizedim[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.
CodePudding user response:
Recursion is a functional heritage and so using it with functional style yields the best results. This means avoiding things like mutation, variable reassignments, and other side effects.
Additionally, your input is over-specified. The last number isn't needed as the output can be determined without it -
function nest (t, q) {
if (q.length < 1)
return t
else
return cut(t, t.length/q[0]).map(r => nest(r, q.slice(1)))
}
function cut (t, n) {
if (n >= t.length)
return [t]
else
return [t.slice(0,n), ...cut(t.slice(n), n)]
}
const A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
console.log(JSON.stringify(nest(A, [3])))
console.log(JSON.stringify(nest(A, [2,3])))
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
[[1,2,3,4],
[5,6,7,8],
[9,10,11,12]]
[[[1,2],
[3,4],
[5,6]],
[[7,8],
[9,10],
[11,12]]]
⚠️ Expect unexpected output when q
inputs are not factors of t.length