其实最核心的思路就是递归,如果单纯用编程语言实现,而不是使用一些巧妙的API的话,本质的思路就是递归,因为JS数组多层嵌套,实现扁平化的过程其实就是层层递归取出元素的过程,这里给出三种实现JS数组扁平化的方法。
- 纯递归实现
- 扩展运算符
- 降维打击
纯递归实现
算法的步骤是这样的:
- 顺序扫描初始数组{arr}的第一维,取元素element,若element还是数组则执行3,若element是单个元素则执行2
- 将单元素加入newArr的一维数组中
- 把{element}数组作为新的初始数组,执行1
转化为JS代码,可以这样写:
function(arr,newArr){
arr.forEach(element => {
if(!Array.isArray(element)){
newArr.push(element);
}else{
return arguments.callee(element,newArr);
}
});
return newArr;
}
扩展运算符
首先要了解ES6中的扩展运算符
...
, 三点运算符可以将二维数组直接扁平化
算法的步骤是这样的:
- 判断初始数组{arr}是否至少是二维数组,也就是说arr数组中是否包含数组项,若包含则执行2,若不包含则执行3
- 使用扩展运算符对数组扁平化,并将扁平化后数组{arr}置为初始数组,然后以此为参数执行1
- 已经扁平化为一维数组了,直接返回结果
转化为JS代码,可以这样写:
function(arr){
if(!arr.some(element => {
return Array.isArray(element);
})){
return arr;
}else{
arr = [].concat(...arr);
return arguments.callee(arr);
}
}
降维打击
这是巧妙使用JS的API
toString方法
来实现的,调用Array.prototype.toString
,会返回将数组中的元素使用,
连接起来的字符串
思路很简单,就是数组被toString方法
降维后的字符串使用split
方法还原为一维数组。
但是这里需要处理一个问题,就是如果数组中的元素是数字而不是字符或字符串,那么split
切割还原后的字符或字符串需要转换为数字。这里我使用||
运算符做了一个巧妙的适配。
function(arr){
return arr.toString().split(',').map(function(val){
return parseInt(val) || parseFloat(val) || val;
});
}
这段代码是不是很简洁,这也是我喜欢JS这门语言的原因,可以写出一些超级简洁干净的代码,赏心悦目?
最后,我们重构一下代码
最近在看设计模式,这里我们使用不同的算法和表达实现了同一种能力,但是有些函数的参数不尽相同,为了易于维护,我们不妨写一个代理执行的函数,来屏蔽掉原函数的异构型。
//最普通的方式,递归实现,遇到是数组的元素就递归
function common(arr,newArr){
arr.forEach(element => {
if(!Array.isArray(element)){
newArr.push(element);
}else{
return arguments.callee(element,newArr);
}
});
return newArr;
}
//降维打击 : 利用了toString方法的特性,或者是join方法也可以
function reduceDimen(arr){
return arr.toString().split(',').map(function(val){
return parseInt(val) || parseFloat(val) || val;
});
}
//扩展运算符 和 递归 结合使用
function extendOpt(arr){
if(!arr.some(element => {
return Array.isArray(element);
})){
return arr;
}else{
arr = [].concat(...arr);
return arguments.callee(arr);
}
}
//代理执行,屏蔽掉不同函数的参数异构,又使得算法表达可配置
var flatten = function(func,arr) {
if(arguments.length === 1){
console.log(common(func,[]));
return;
}
if(func === common){
console.log(func(arr,[]));
return ;
}
console.log(func(arr));
}
//测试
var arr = [
[1,2,[
10,34,22
]],
[[
2,3,58
],2,5],
[6,4,9]
];
flatten(arr);
flatten(common,arr);
flatten(reduceDimen,arr);
flatten(extendOpt,arr);
//结果均输出 : [ 1, 2, 10, 34, 22, 2, 3, 58, 2, 5, 6, 4, 9 ]