数组扁平化
的公众号文章,仔细理解把几个方法试了一下之后感觉受益良多,在此基础上我又查询了其他几种方法,归纳整理后决定写下这篇文章。
什么是“数组扁平化”
用简单的话来说,就是将一个多维数组
变为一个一维数组
。例如,将数组[1, 2, [3, [4, 5]], [6, 7]]扁平化处理后输出[1, 2, 3, 4, 5, 6, 7]。
实现“数组扁平化”方法
声明一个函数,遍历数组的每个元素,判断当前元素是否仍是数组,是的话递归执行这个函数,并把执行结果与当前结果数组合并,不是数组则直接将当前元素push
到结果数组中。
function flatten(arr) {
let result = [];
// 此处也可使用for...of遍历
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;
}
与第一种方法思路是一样的,区别在于这里利用reduce
函数的特性遍历数组并保存每一次的计算结果。
function flatten(arr) {
return arr.reduce((pre, current) => {
if (Array.isArray(current)) {
return pre.concat(flatten(current));
} else {
return pre.concat(current);
}
}, []);
},
对于数组对象,toString
方法连接数组并返回一个字符串,其中包含用逗号分隔的每个数组元素。返回的字符串使用split
分割成子字符串数组,最后将数组中每个元素的类型转换为Number
型。
function flatten(arr) {
return arr.toString().split(',').map((item) => Number(item));
},
为了方便理解,在浏览器调试工具的Console下逐步执行各个步骤,每步的输出结果如下图所示。
在while
循环中,使用findIndex
判断当前数组是否是一个多维数组(即判断数组是否存在Array
类型的元素),如是,则使用…
扩展操作符展开作为concat
方法的参数进行合并(如下图)并赋值给当前数组,再执行下一次循环的条件判断,直至得到一个一维数组。
function flatten(arr) {
while (arr.findIndex((item) => Array.isArray(item)) > 0) {
arr = [].concat(...arr);
}
return arr;
}
可能有些小伙伴不太能理解 arr = [].concat(...arr)
;这一行代码,其实这一行代码的作用就相当于把所给多维数组剥开一层(如下图所示),多次循环执行直至得到一个一维数组。
直接使用ES6提供的flat
方法实现扁平化。falt()
方法会按照指定的深度递归遍历数组,arr.flat([depth])
,参数depth
不填时默认值为1,depth
为Infinity
表示展开任意深度
的嵌套数组。
function flatten(arr) {
return arr.flat(Infinity);
}
使用JSON的序列化函数stringify()
先对数组进行序列化,再用正则去掉[]
,得到的结果在最外层加上[]
后使用JSON.parse()
恢复成数组对象。
function flatten(arr) {
let result = JSON.stringify(arr).replace(/(\[|\])/g,'');
result = '[' + result + ']';
return JSON.parse(result);
}
创建一个栈结构和一个存放结果的空数组,然后遍历栈结构,判断元素如果是数组就使用扩展操作符展开再次入栈,不是就添加到结果数组的开头。
// 无递归数组扁平化
function flatten(arr) {
const stack = [...arr];
const res = [];
while (stack.length) {
// 出栈 从 stack 中取出一个元素
const next = stack.pop();
if (Array.isArray(next)) {
// 展开一层重新入栈
stack.push(...next);
} else {
res.unshift(next);
}
}
return res;
}
Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。思路还是遍历当前数组,判断数组元素是否是数组,是则使用 yield 语句递归执行这个 Generator 函数,不是则使用 yield
表达式返回当前值。
function* flatten(arr){
for(const item of arr) {
if(Array.isArray(item)) {
yield* flatten(item);
} else {
yield item;
}
}
}
const array = [1, 2, [3, [4, 5]], [6, 7]];
const flattened = [...flatten(array)];
留下足迹~
参考文章 传送门 @j-ymg