# 原创:JavaScript 获取数组深度
计算数组的长度,给出以下例子,计算出数组的深度。
arrayDeepLevel([1, 2, [3, [1, [0]]]])
,长度为3
arrayDeepLevel([])
,长度为0
arrayDeepLevel([[[]]]
,长度为2
arrayDeepLevel([0, [2], [2, [3]]])
,长度为3
# 分析
默认最小是
0
只计算是数组结构
第一反应过来,就是要递归循环。
所以起初构造了以下函数
let level = -1;
const arrayDeepLevel = function(array) {
return function(data) {
if (Array.isArray(data)) {
for (let item of data) {
if (Array.isArray(item)) {
arrayDeepLevel(item);
}
}
level++;
return level;
}
};
};
通过验证,显示上面是成功的,但是,仅是单次使用,比如执行多次后,全局变量 level
就一直累加,显然不是我们想要的结果哦。
关键的一点就是,大函数只执行一次,递归是在内部构建,于是有了声明第二个函数的改造。
const arrayDeepLevel = function(array) {
let level = -1;
const recursion = function(data) {
if (Array.isArray(data)) {
for (let item of data) {
if (Array.isArray(item)) {
recursion(item);
}
}
level++;
return level;
}
};
return recursion(array);
};
module.exports = arrayDeepLevel;
保证了多次执行的值都是被初始掉。
# 拓展以及延伸
曾在一个项目中处理过类似的问题。
简化后,通过移除非数组的元素,我们得到下面的结构比较:
[1,2,3,[5,6]] => [[]]
[1,[2,[3,[]]]] => [[[[]]]]
...
我们通过这个结构 [[[[]]]]
,认为是一个字符串 '[[[[]]]]'
。
为了更形象的描述 [
始终对应 ]
构成一个 组合。
如下:
形象化: "a,b,c,d d1,c1,b1,a1"
对应的 | | | | | | | |
原始字符 [,[,[,[ ], ], ], ]
序号: 0 1 2 3 4 5 6 7
于是得到:
a index = 0
b index = 1
c index = 2
d index = 3
d1 index = 4
c1 index = 5
b1 index = 6
a1 index = 7
得出并收集它们的索引值关系:
0 1, 2, 3
↓ ↓ ↓ ↓
4 5 6 7
经过一个 level 提取算法 (opens new window) 的实现,将得到一个有趣的现象:
公式:当前 index
x 2 - value
= 对应的 level
我们对 [0,1,2,3]
,通过算法转换如下:
index | 0 | 1 | 2 | 3 |
---|---|---|---|---|
value | 0 | 1 | 2 | 3 |
index *2 - value | 0*2-0=0 | 1*2-1=1 | 2*2-2=2 | 3*2-3=1 |
或许有人说,这个功能可能是个巧合,不妨看一下下面的:
已知,我们的结构是 [[[][]]]
,此时,左包围是对应索引与右括号的关系是 ,
0 1, 2, 4
↓ ↓ ↓ ↓
7 2 6 5
根据公式转换如下:
index | 0 | 1 | 2 | 4 |
---|---|---|---|---|
value | 0 | 1 | 2 | 3 |
index *2 - value | 0*2-0=0 | 1*2-1=1 | 2*2-2=2 | 3*2-4=2 |
直到这里,我们得出一个结论,只要知道左边的索引值,就可以对应的找到它合并为一个组合所在的索引值(即左边 [
,找到匹配右边结束的 ]
),以及它对应的 level。
这个算法被我应用于一款 HTML 转 Markdown 工具 Pyhtmd (opens new window),作为解析 HTML 列表元素 为 markdown 代码的核心支撑。
得到最大 level 的深度,只要 Math.max.apply(this,[0,1,2,2])
即可。
下面是完整的代码实现:
const arrayDeepLevel = function(array) {
console.time("get-array-deep-level-test-2==>");
const arrayStr = JSON.stringify(array);
let clearArrayStr = "";
// 这里的正则没有写好
arrayStr.replace(/(?:(\[|\]))/g, function($1) {
clearArrayStr += $1;
return $1;
});
const leftStrItems = [];
// const rightStrItems = [];
for (let i = 0; i < clearArrayStr.length; i++) {
// start tag
if (clearArrayStr[i] === "[") {
leftStrItems.push(i);
}
}
const leftMaps = {};
for (let i = 0; i < leftStrItems.length; i++) {
const item = leftStrItems[i];
leftMaps[item] = i * 2 - item;
}
const levelArray = Object.values(leftMaps);
console.timeEnd("get-array-deep-level-test-2==>");
// 0.113037109375 ms,咋一看时间复杂度是O(n),但这里空间复杂度很高,加上其他多余的操作
return Math.max.apply(this, levelArray);
};
module.exports = arrayDeepLevel;
it("4. ==> level:3", () => {
// 因为原题目是元素的包括了自己,实际上这里最高二级,是针对外包围计算,而非元素
expect(arrayDeepLevel([0, [1], [1, [2]]])).toBe(2);
});