前端手写-数组扁平化

题目描述:
已有多级嵌套数组 : [1, [2, [3, [4, 5]]], 6] 将其扁平化处理 输出: [1,2,3,4,5,6]

题目考查的内容就是数组扁平化,什么是扁平化呢?
扁平化:就是将多维数组变成一维数组,不存在数组的嵌套

扁平化的方法:

  1. ES6 flat
  2. toString
  3. 正则替换
  4. 循环递归:循环+concat+push / 使用参数控制扁平化深度 / reduce / generator
  5. 使用栈结构
  6. while循环+some

1.ES6 flat

flat(depth) 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
🌟 参数:depth(可选)指定要提取嵌套数组的结构深度,默认值为1
🌟 返回值:返回一个新数组,可展开任意深度的嵌套数组

1
let res = arr.flat(Infinity);

2.toString方法

1
2
3
function _flatten(arr){
return arr.toString().split(',').map(item=>parseFloat(item));
}

3.正则替换

看到嵌套数组,从字符串的角度上看就是多了很多的[],将它们替换就可以实现简单的扁平化

1
2
3
4
5
6
function _flatten(arr){
let str = JSON.stringify(arr).replace(/(\[|\])/g,'');
str = '['+str+']';
arr = JSON.parse(str);
return arr;
}

4.循环递归

4.1 循环+concat+push

🌟思路:

  1. 循环判断数组的每一项是否是数组: Array.isArray(arr[i])
  2. 是数组就递归调用上面的扁平化一层的代码 result = result.concat(flatten(arr[i]));
  3. 不是数组,直接通过push添加到返回值数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function _flatten(arr) {
let result = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]));
} else {
result.push(arr[i])
}
}
return result
}

// forEach版本
// 递归版本的反嵌套
function flatten(array) {
var flattend = [];
(function flat(array) {
array.forEach(function(el) {
if (Array.isArray(el)) flat(el);
else flattend.push(el);
});
})(array);
return flattend;
}
4.2 使用参数控制扁平化深度

🌟:手写flat()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// forEach 遍历数组会自动跳过空元素
const _flat = (arr = [], depth = 1) => {
const result = []; // 缓存递归结果
// 开始递归
(function flat(arr, depth) {
// forEach 会自动去除数组空位
arr.forEach((item) => {
// 控制递归深度
if (Array.isArray(item) && depth > 0) {
// 递归数组
flat(item, depth - 1)
} else {
// 缓存元素
result.push(item)
}
})
})(arr, depth)
// 返回递归结果
return result;
}
4.3 巧用reduce

reduce 方法为数组中的每个元素按序执行一个reducer函数,每一次运行 reducer 会将先前元素的计算结构作为参数传入,最后将其结果汇总为单个返回值。

1
2
3
4
5
6
7
8
9
10
const arr = [1, [[2, 3], 4],5]
const flatten = (arr, deep = 1) => {
if (deep <= 0) return arr;
return arr.reduce((res, curr) => res.concat(Array.isArray(curr) ? flatten(curr, deep - 1) : curr), [])
}
// function flatten (arr,deep=1) {
// return arr.reduce((acc,val) => acc.concat(Array.isArray(val)? flatten(val,deep-1):val),[])
// }
console.log(arr, Infinity);
// 输出:[ 1, 2, 3, 4, 5, 6 ]
4.4 使用Generator函数

GeneratorFunction是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。它不同于普通函数,是可以暂停执行的,所以函数名之前要加星号,以示区别。整个 Generator 函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用 yield 语句注明。Generator 函数的执行方法如下。
构造器生成新的生成器函数。

1
2
3
4
5
6
7
8
9
10
function* flatten(array) {
for (const item of array) {
if (Array.isArray(item)) {
yield* flatten(item);
} else {
yield item;
}
}
}

5.使用栈结构

🪐 思路:

  1. 把数组通过一个栈来维护
  2. 当栈不为空的时候循环执行处理
  3. pop()将栈尾出栈
  4. 如果出栈的元素是数组,就将该元素解构后每一元素进行入栈操作
  5. 出栈的元素不是数组就push进返回值res
  6. 反转恢复原数组的顺序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];
function flatten(arr) {
const stack = [...arr];
const res = [];
while (stack.length) {
// 使用 pop 从 stack 中取出并移除值
const next = stack.pop();
if (Array.isArray(next)) {
// 使用 push 送回内层数组中的元素,不会改动原始输入
stack.push(...next);
} else {
res.push(next);
}
}
// 反转恢复原数组的顺序
return res.reverse();
}
flatten(arr1);// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

6.while循环+some方法

some :方法测试数组中是不是至少有 1 个元素通过了被提供的函数测试。它返回的是一个 Boolean 类型的值。

🪐 思路:
通过some来判断数组中是否用数组,通过while不断循环执行判断, 如果是数组的话可以使用 拓展运算符... 每次只能展开最外层的数组,加上contact来减少嵌套层数

1
2
3
4
5
6
7
8
9
function flatten(arr) {
while (arr.some(item=> Array.isArray(item))) {
console.log(...arr)
arr = [].concat(...arr)
console.log(arr)
}
return arr
}
console.log(flatten(arr));
文章作者: qinwei
文章链接: https://qw-null.github.io/2022/09/15/前端手写-数组扁平化/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 QW's Blog