【骚操作】JS带你飞,嵌套数组深度计算轻松搞定!

【骚操作】JS带你飞,嵌套数组深度计算轻松搞定!

前言

在前端开发中,经常会遇到需要处理多维嵌套的数据结构。而对于这些多维嵌套的数据结构,往往需要计算出它们的深度,用于方便后续处理。本文将介绍使用JavaScript实现计算多维嵌套数组深度的方法。

理论知识

在了解具体实现前,先来了解一下相关的理论知识:多维数组的深度。所谓数组的深度,就是指这个数组里面嵌套了多少层子数组。如下图所示:

[1, 2, 3, 4]        // 深度为 1
[[1, 2], [3, 4]]    // 深度为 2
[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]  // 深度为 3

可以看出,第一种情况只有一层,第二种情况有两层,第三种情况有三层。

实现思路

根据上述定义,计算一个数组的深度其实就是递归遍历每一层子数组,并不断加一的过程。因此,我们可以采用递归的思想,实现如下:

function getDepth(arr) {
  if (!Array.isArray(arr)) {   // 判断是否为数组
    return 0;
  }
  let depth = 1;               // 初始化深度为 1
  for (let i = 0; i < arr.length; i++) {
    const cur = arr[i];
    if (Array.isArray(cur)) {  // 如果当前元素仍为数组,递归遍历
      const curDepth = getDepth(cur) + 1;
      depth = Math.max(depth, curDepth);
    }
  }
  return depth;
}

上述代码中,首先进行了类型判断,如果不是数组,则直接返回“0”;否则,逐层遍历每一层子数组,通过递归调用函数计算出每个子数组的深度,并记录最大深度。

实例演示

我们可以利用上述方法对以下多维嵌套数组进行深度计算:

const arr1 = [1, 2, 3, 4];                  // 深度为 1
const arr2 = [[1, 2], [3, 4]];             // 深度为 2
const arr3 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]];  // 深度为 3

console.log(getDepth(arr1));                // 输出 1
console.log(getDepth(arr2));                // 输出 2
console.log(getDepth(arr3));                // 输出 3

在控制台输出结果如下:

1
2
3

此外,我们还可以对一些嵌套层数较深的数组进行计算:

const arr4 = [[[[1, 2], [3, 4]], [[5, 6], [7, 8]]],
              [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]]; // 深度为 4

console.log(getDepth(arr4));                // 输出 4

性能优化

在实际开发中,如果处理的数据量很大,单纯使用递归的方法可能会耗费大量时间和内存资源。因此,在设计算法时应该尽可能地减少时间复杂度和空间复杂度。

以下是一些可能比较好的优化方案:

方案一:队列迭代

队列迭代法同样可以获取多维嵌套数组的深度,而且有时候运行速度更快。我们可以使用一个队列来存储每一层子数组,并不断出队并将其所有元素压入队列中,直到队列为空为止。我们可以通过记录队列的大小来控制深度的增加,具体实现如下:

function getDepthByQueue(arr) {
  if (!Array.isArray(arr)) {  // 判断是否为数组
    return 0;
  }
  let depth = 1;              // 初始化深度为 1
  const queue = [arr];        // 将初始数组放入队列中
  while (queue.length) {      // 如果队列不为空
    const curLevelSize = queue.length;
    for (let i = 0; i < curLevelSize; i++) {
      const cur = queue.shift();     // 出队一个子数组
      if (Array.isArray(cur)) {
        queue.push(...cur);          // 将其中所有元素入队
      }
    }  
    depth++;                        // 深度加一
  }
  return depth - 1;                 // 最后在队列为空时,depth 多增加了一次,故需要减一
}

方案二:reduce计数

通过使用reduce方法,可以实现对多维嵌套数组的深度进行计数。在这种方法里,我们只需要遍历每一个元素,并让其值等于当前递归所得到的深度加一即可。

function getDepthByReduce(arr) {
  if (!Array.isArray(arr)) {   // 判断是否为数组
    return 0;
  }
  return arr.reduce(function(pre, cur) {
    const curDepth = getDepthByReduce(cur) + 1;
    return Math.max(pre, curDepth);
  }, 1)
}

异常处理

在正常情况下,多维嵌套数组的深度是可以被正常计算的。但是在某些边界条件下,我们需要对计算过程进行异常处理:

边界条件一:空数组

对于空数组,其深度为0。

console.log(getDepth([]));   // 输出 0

边界条件二:不是数组

如果传入的值不是数组类型,返回0即可。

console.log(getDepth("test"));    // 输出 0
console.log(getDepth({ a: 1 }));  // 输出 0
console.log(getDepth(123));      // 输出 0

边界条件三:无限递归

在某些特殊情况下,可能会出现无限递归的错误。例如一个由自己本身构成的数组,此时就会导致函数陷入死循环。因此,在编写代码时需要避免这种恶性递归行为。

const test = [];
test.push(test);
console.log(getDepth(test));    // 此处会出现无限递归的错误

为了避免无限递归的问题,可以设置一个计数器。当函数调用次数超过一定值时,抛出异常并阻止递归的继续进行。

function getDepthWithLimit(arr, limit = 10000) {
  let count = 0;
  function calculateDepth(cur) {
    if (!Array.isArray(cur)) {
      return 0;
    }
    if (count++ > limit) {        // 超过极限次数则返回 Infinity
      throw new Error("too much recursive");
    }
    const curDepth = Math.max(...cur.map(calculateDepth)) + 1;
    return curDepth;
  }
 
  try {
    return calculateDepth(arr);
  } catch (e) {
    console.warn(e.message);
    return Infinity;
  }
}

在函数中增加计数器,每经过一次递归就自增,如果达到某个条件(limit)就抛出异常,并阻止递归的执行。最后用try…catch来捕获异常。

结尾

我们可以看到使用JavaScript计算多维嵌套数组的深度十分方便。只需采用递归的思路,遍历每一个子数组,并记录最大深度即可。

但需要注意的是,在实际开发中,如果多维嵌套层数过深,会导致递归调用栈溢出的问题。因此,在实现该方法时需要考虑到性能优化和异常处理。

以下是实现时的一些注意点:

  • 尽量避免对传入参数进行修改,否则可能会影响其它部分代码。
  • 在递归过程中要注意边界条件的处理,以防止无限递归或者数组越界的情况发生。
  • 对于反复出现的计算结果可以进行缓存,以提高代码执行效率。

原文链接:https://juejin.cn/post/7240090805313732666 作者:𝑺𝒉𝒊𝒉𝑯𝒔𝒊𝒏𝒈

(0)
上一篇 2023年6月3日 上午10:17
下一篇 2023年6月3日 上午10:27

相关推荐

发表回复

登录后才能评论