探究JavaScript中数组扁平化的方式

数组扁平化,又称数组拍平,是一种将多维数组降维打击之后变成一维数组的办法。

与深浅拷贝一样也是在面试里出现过,而实际开发中见得较少。这里记录一下,学习学习。

数组扁平化的目标举例:现在有一个数组是[1,[2,[3,4]]],要把它高维的部分拍扁,变成[1,2,3,4]

一个直观的做法就是递归,遍历元素,当目前元素是数值,那就加入到新数组,如果是引用类型(数组),那就递归遍历这个数组。

这样的做法大概做法如下:

1
2
3
4
5
6
7
8
9
10
11
let target = [];
function flatten(arr) {
for (let el of arr) {
if (typeof el === 'object') {
flatten(el);
}
else {
target.push(el);
}
}
}

这种做法看起来没啥问题,但实际运行起来漏洞百出。对于数组里面元素只有数字的还好,但如果啥都有的话,就会报错。

那咱转化成另一种遍历方式?

1
2
3
4
5
6
7
8
9
10
11
let target = [];
function flatten(arr) {
for (let index = 0; index < arr.length; index++) {
if (typeof arr[index] === 'object') {
flatten(arr[index]);
}
else {
target.push(arr[index]);
}
}
}

嗯,这样是可以跑了,但是,对于下面这个巨奇怪的数组:

1
2
3
4
5
6
7
8
9
10
let arr = [
1,2,
{aaa: 'bbb'},
[2,3,{a:4},[5,[[[[1],2],3]]]],
function () {
return () => {
return 123;
}
},
]

它的结果是:[ 1, 2, 2, 3, 5, 1, 2, 3, [Function] ]。看起来少了点东西?没错,里面的对象没了。这说明我们的判断方法有问题。

再换一种方式,这次使用Array.isArray方法进行判定,然后把这个有点视觉观感不太好的if换成三目,就是下面这样:

1
2
3
4
5
6
let target = [];
function flatten(arr) {
for (let index = 0; index < arr.length; index++) {
Array.isArray(arr[index]) ? flatten(arr[index]) : target.push(arr[index]);
}
}

测试输出[ 1, 2, { aaa: 'bbb' }, 2, 3, { a: 4 }, 5, 1, 2, 3, [Function] ],这是我们想要的结果。

其实也可以使用ES6中的新方法reduce处理这个事情。先摘一下我之前记录JavaScript数组操作时的笔记:

reduce方法接收一个有以下四个参数的函数:previousValuecurrentValueindexarray,后两个参数是可选的。这个函数会返回一个将被叠加到累加器的值,方法停止执行后会返回这个累加器。如果要对一个数组中所有元素求和,这个就比较有用。

使用reduce处理拍平的操作思路也是递归。这里还使用到了展开运算符,两者一结合,写出来的代码就比较优美了。

1
2
3
4
5
function flatten(arr) {
return arr.reduce((pre,cur) => {
return Array.isArray(cur) ? [...pre, ...flatten(cur)] : [...pre, cur];
},[])
}

那既然都考虑到ES6了,ES6里面就没有可以直接完成这个操作的函数吗?其实是有的。一行解决。

1
arr.flat(Infinity)

参数里传入的是扁平化的深度,那要彻底扁平的话就传入一个Infinity就可以了。

还有没有其他方法呢?有一种使用toString的方法,但是效果并不好,对于复杂的结构不能处理,这里给出查找到的一种做法参考。

1
2
3
4
5
function flat(arr) {
return arr.toString().split(',').map((val)=>{
return parseInt(val)
})
}

最后是一种比较神的做法,它使用的是apply和some,有点高级。这个留个坑,以后再慢慢研究。

1
2
3
4
5
6
function flat(arr) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat.apply([],arr);
}
return arr;
}
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2018-2023 Shawn Zhou
  • Hexo 框架强力驱动 | 主题 - Ayer
  • 访问人数: | 浏览次数:

感谢打赏~

支付宝
微信