定义 : 扁平化就是将多维数组变成一维数组,不存在数组的嵌套
flat(depth) 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
参数:
depth
(可选) 指定要提取嵌套数组的结构深度,默认值为 1
返回值:
返回一个新数组,包含数组与提取嵌套数组的所有元素的新数组
使用 Infinity
,可展开任意深度的嵌套数组
封装思路: 使用 es6 自带 API 处理
const arr = [1, [2, [3, [4, 5]]], 6]
function flatten(params) {
return params.flat(Infinity)
}
console.log(flatten(arr)); // 输出: [1,2,3,4,5,6]
得分 : ⭐
直接使用自带的方法可以很快的实现, 但是面试官当然不希望就看到这些呀 !
如果数组的项全为数字,可以使用join(),toString()可以利用数组toString() 转为字符串
function flatten(arr) {
return arr.toString().split(',').map(item =>parseFloat(item))
}
console.log(flatten(arr)); // 输出:[ 1, 2, 3, 4, 5, 6 ]
得分 : ⭐ (并不是要考你的数组的方法调用)
看到嵌套的数组,如果在字符串的角度上看就是多了很多[
和]
,如果把它们替换就可以实现简单的扁平化
function flatten (arr) {
console.log('JSON.stringify(arr)', typeof JSON.stringify(arr))
let str= JSON.stringify(arr).replace(/(\[|\])/g, '');
str = '[' + str + ']'; arr = JSON.parse(str); return arr
} console.log(flatten(arr))
**得分 : **⭐ (并不是要考你的数组的方法调用)
当只有一层嵌套数组使用push的方式扁平化
[1, [2, 3,4,5,6]]
let result = []; for (let i = 0; i < arr2.length; i++) {
result = result.concat((arr2[i])); }
console.log(result); [ 1, 2, 3, 4, 5, 6 ]
如果有多层嵌套的数组就需要使用 递归的思想 :
思路
Array.isArray(arr[i])
result = result.concat(flatten(arr[i]));
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
} console.log(flatten(arr));
或者使用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; }
当然循环可以更改成forEach循环,for of ...等其他循环,简单的循环递归就能够一样的解决啦~
得分: ⭐⭐⭐ (能够使用递归写出数组扁平化,缺少控制层级关系)
这个可以理解为手写flat()
方法啦~
// forEach 遍历数组会自动跳过空元素
const eachFlat = (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; } // for of 循环不能去除数组空位,需要手动去除 const forFlat = (arr = [], depth = 1) => { const result = []; (function flat(arr, depth) { for (let item of arr) { if (Array.isArray(item) && depth > 0) { flat(item, depth - 1) } else { // 去除空元素,添加非 undefined 元素 item !== void 0 && result.push(item); } } })(arr, depth) return result; }
得分: ⭐⭐⭐⭐ (能够使用递归写出数组扁平化,可以通过参数控制层级关系)
reduce 方法为数组中的每个元素按序执行一个
reducer
函数,每一次运行 reducer 会将先前元素的计算结构作为参数传入,最后将其结果汇总为单个返回值
参数:
callbackFn
一个 reducer 函数,包含四个参数:callbackFn
时的返回值,在第一次调用时,若指定了初始值initialValue
,previousVal 的值就位 initialValue,否则初始值就是为数组的索引为 0 的元素currentVal
:数组中正在处理的元素,在第一次调用时,若指定了初始值,其值则为数组索引为 0 的元素 array[0],否则为 array[1]initialValue
(可选) : 作为第一次调用 callback 函数时参数 previousValue 的值返回值: 使用 reducer 回调函数遍历整个数组后的结果
思路:
当我们使用 reduce 来解析第一层数组,可以得到:
const arr = [1, [[2, 3], 4],5]
const result = arr.reduce((acc, val) => acc.concat(val), []);
console.log(result); // 输出: [1,[2,3],4,5]
可以看出上面的代码可以扁平化一层数组,对于多层级嵌套的数组, 这个时候就需要使用递归的思想来解决问题了,再次遍历数组,发现数组元素任然是数组的时候,再次执行上面扁平化
手写方法
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 ]
得分: ⭐⭐⭐⭐ (能够使用递归写出数组扁平化,巧用reduce方法可加分)
Generator
函数GeneratorFunction是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。
它不同于普通函数,是可以暂停执行的,所以函数名之前要加星号,以示区别。
整个 Generator 函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用 yield 语句注明。Generator 函数的执行方法如下。
构造器生成新的生成器函数
function* flatten(array) {
for (const item of array) {
if (Array.isArray(item)) {
yield* flatten(item);
} else { yield item; } } }
得分: ⭐⭐⭐ (使用Generator 函数 进行递归)
递归循环都可通过维护一个堆结构来解决
如果不使用递归数组来实现扁平化,可以使用堆栈来解决
深度的控制比较低效,因为需要检查每一个值的深度
思路:
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]
得分: ⭐⭐⭐⭐ (使用数据结构栈的特性取代递归操作,减少时间复杂度)
some :方法测试数组中是不是至少有 1 个元素通过了被提供的函数测试。它返回的是一个 Boolean 类型的值。
思路
通过some来判断数组中是否用数组,通过while不断循环执行判断, 如果是数组的话可以使用 拓展运算符...
... 每次只能展开最外层的数组,加上contact
来减少嵌套层数,
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));