如何在 Javascript 中将展平数组重塑为任意形状的多维数组?

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

[我有什么]

具有 n 个元素的扁平化或一维数组,例如数组 A 下面有 12 个项目。

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

[我想做什么]

将 A 重塑为多维数组 B,其 形状 由数组 C 确定,可能会因其他条件而异。

// 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... 

[我试过的]

我找到了以下参考资料,它可以按任意行数将展平数组展开为二维数组: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; 
}

[我还没想通]

我还没有想出如何制作“动态嵌套 for 循环”,或者需要某种递归,以将一维数组重塑为由另一个数组确定的任意形状的多维数组。

感谢帮助。

这是我的解决方案:


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 是一个递归函数。由于闭包,它可以访问 elemIndexarrdimelemIndex指的是从数组arr.

中读取的当前元素的索引

_nest取当前维度的索引:dimIndex。它首先用 0.

调用
  • 如果dimIndex 引用dim 数组中的最后一个维度,则必须返回相应大小的一维数组。这是递归的基本条件。它 returns 从 elemIndex 开始的 arr 的一片,大小 dim[dimIndex]
  • 否则它使用下一个维度调用 _nest dim[dimIndex] 次。例如,当 dimIndex 为 0,即大小为 3 => 我们需要 3 个数组,因此我们调用 _nest 三次,每个数组的大小在上面的示例中为 4。

递归是一种函数式继承,因此将它与函数式风格一起使用会产生最佳效果。这意味着要避免突变、变量重新分配和其他副作用。

另外,您的输入是过度指定的。不需要最后一个数字,因为没有它就可以确定输出 -

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])))

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

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

⚠️ 当 q 输入不是 t.length

的因数时,预计会有意外输出