目录
方法一:使用flat() *ES6以后的项目推荐
说明:flat()方法是ES10提出的,它会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。(flat意为“水平的;平坦的”)
let arr = [1,2,3,4,5,6,[7,8,[9,[10,11],12],13],14,15,16]
// 方法一:使用flat()
// Infinity:无限循环 指定深度为无限
const flatArr = arr.flat(Infinity)
console.log(flatArr)
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 , 13, 14, 15, 16]
// 指定深度为 1
const flatArr1 = arr.flat(1)
console.log(flatArr1)
// [1, 2, 3, 4, 5, 6, 7, 8, [9, [10, 11], 12] , 13, 14, 15, 16]
// 指定深度为 2
const flatArr2 = arr.flat(2)
console.log(flatArr2)
// [1, 2, 3, 4, 5, 6, 7, 8, 9, [10, 11], 12 , 13, 14, 15, 16]
// 指定深度为 3
const flatArr3 = arr.flat(3)
console.log(flatArr3)
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 , 13, 14, 15, 16]
方法二:使用正则 + JSON *不推荐
说明:不建议使用此方法,因为会改变数据类型
// 未优化的会把元素变成字符串类型
let arr = [1,2,3,4,5,6,[7,8,[9,[10,11],12],13],14,15,16]
// 把数组先转成JSON格式,再利用replace方法使用正则来替换掉里面的 [ 与 ] 符号,最后使用split方法把字符串 转 数组
const result = JSON.stringify(arr).replace(/\[|\]/g, '').split(',')
console.log(result)
// ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16'] 数组元素都变成了字符串
// 优化后的处理方法
let arr = [1,2,3,4,5,6,[7,8,[9,[10,11],12],13],14,15,16]
// 把数组先转成JSON格式
// 再利用replace方法使用正则来替换掉里面的 [ 与 ] 符号
// 再JSON格式的字符串外面加上数组的 [ 与 ] 符号
// 再使用parse方法解析带了[ 与 ] 符号的 字符串
const result = JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']')
console.log(result)
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
方法三:使用reduce()+concat()
说明:使用reduce拿到数组的当前值和前一项值,判断当前值是否为数组,初始值设置为[],然后使用concat进行数组合并。
- reduce()方法:对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
- concat()方法:用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
// 上面说的方式大家估计还是很懵的,我下面把reduce的执行流程拆开一步步说明
// 其实里面还是包含了递归的用法
let arr = [1,2,[3,4,[5,[6,7],8],9],10]
function flatten(arr) {
return arr.reduce((pre, current) => {
return pre.concat(Array.isArray(current) ? flatten(current) : current),[])
}
}
const result = flatten(arr)
console.log(result)
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// flatten 函数中发生的过程解析
// 当调用flatten 并传入arr 使用reduce去执行 升序 子元素 合并 [] 数组
// 第一遍:执行的结果为: pre 等于 [] , current 等于 1 , 合并 1 返回结果为 [1]
// 等同 [].concat(1)
// 第二遍:执行的结果为: pre 等于 [1] , current 等于 2 , 合并 2 返回结果为 [1,2]
// 等同 [1].concat(2)
// 等待返回 递归返回 [3,4,[5,[6,7],8],9] 扁平化后的结果[3,4,5,6,7,8,9] 才能继续往下合并
-----------------------------------------------------------------------------------------
// 第三遍:执行的结果为: pre 等于 [1,2] , current 等于 数组[3,4,[5,[6,7],8],9]
// 由于current是一个数组 所以再自调用一次flatten函数 等同是递归 为了方便后面继续解析 我给它一个命名为: 递归1层
// 递归1层第一次 中 arr的值为:[3,4,[5,[6,7],8],9] 执行reduce之后的 pre为[] current等于3, 合并3 返回结果为 [3]
// 等同 [].concat(3)
// 递归1层第二次 中 arr的值为:[3,4,[5,[6,7],8],9] 执行reduce之后的 pre为[3] current等于4, 合并4 返回结果为 [3,4]
// 等同 [3].concat(4)
// 等待返回 递归返回 [5,[6,7],8] 扁平化后的结果[5,6,7,8] 才能继续往下合并
-----------------------------------------------------------------------------------------
// 递归1层第三次 pre 等于 [3,4] , current 等于 数组[5,[6,7],8]
// 由于current是一个数组 所以再自调用一次flatten函数 等同是递归 为了方便后面继续解析 我给它一个命名为: 递归2层
// 递归2层第一次 arr的值为:[5,[6,7],8] 执行reduce之后的 pre为[] current等于5, 合并5 返回结果为 [5]
// 等同 [].concat(5)
// 等待返回 递归返回 [6,7] 扁平化后的结果[6,7] 才能继续往下合并
-----------------------------------------------------------------------------------------
// 递归2层第二次 pre 等于 [5] , current 等于 数组[6,7]
// 由于current是一个数组 所以再自调用一次flatten函数 等同是递归 为了方便后面继续解析 我给它一个命名为: 递归3层
// 递归3层第一次 arr的值为:[6,7] 执行reduce之后的 pre为[] current等于6, 合并6 返回结果为 [6]
// 等同 [].concat(6)
// 递归3层第二次 arr的值为:[6,7] 执行reduce之后的 pre为[6] current等于7, 合并7 返回结果为 [6,7]
// 等同 [6].concat(7)
// 第3层递归结束,返回[6,7] 给递归2层
-----------------------------------------------------------------------------------------
// 继续递归2层第二次 pre 等于 [5] , current 等于 [6,7] 合并[6,7] 返回结果为 [5,6,7]
// 等同 [5].concat([6,7])
// 继续递归2层第三次 pre 等于 [5,6,7] , current 等于 8 合并8 返回结果为 [5,6,7,8]
// 等同 [5,6,7].concat(8)
// 第2层递归结束,返回[5,6,7,8]给递归1层
-----------------------------------------------------------------------------------------
// 继续递归1层第三次 pre 等于 [3,4] , current 等于 [5,6,7,8] 合并[5,6,7,8] 返回结果为 [3,4,5,6,7,8]
// 等同 [3,4].concat([5,6,7,8])
// 继续递归1层第四次 pre 等于 [3,4,5,6,7,8] , current 等于 9 合并9 返回结果为 [3,4,5,6,7,8,9]
// 等同 [3,4,5,6,7,8].concat(9)
// 第1层递归结束,返回[3,4,5,6,7,8,9] 给最外层的reduce
-----------------------------------------------------------------------------------------
// 继续执行第三遍: pre 等于 [1,2] , current 等于 [3,4,5,6,7,8,9] 合并[3,4,5,6,7,8,9] 返回结果为 [1,2,3,4,5,6,7,8,9]
// 等同 [1,2].concat([3,4,5,6,7,8,9])
// 执行第四遍:pre 等于 [1,2,3,4,5,6,7,8,9] , current 等于 10 合并10 返回结果为 [1,2,3,4,5,6,7,8,9,10]
// 到这里flatten函数中的reduce方法正式执行完成 并返回结果 [1,2,3,4,5,6,7,8,9,10]
方法四:使用函数递归 *ES6以前的项目推荐
说明:循环遍历数组,发现含有数组元素就进行递归处理,最终将数组转为一维数组。
let arr = [1,2,[3,4,[5,[6,7],8],9],10]
// 由于需要在递归的过程中把不是数组类型的子元素添加到新的数组中
// 坑点:如果定义在函数中,那会随着递归的实现过程中不断把新的数组初始化,所以必须定义在全局中或局部中,但不能定义在函数中。
const result = []
function flatten(arr){
arr.forEach(item => {
if(Array.isArray(item)){
flatten(item)
}else {
result.push(item)
}
})
}
flatten(arr)
console.log(result)
// [1,2,3,4,5,6,7,8,9,10]
// 这里我只讲递归的过程
// 执行到递归1层这里来的时候 result值为[1,2]
// 执行到递归2层的时候 result值为[1,2,3,4]
// 执行到递归3层的时候 result值为[1,2,3,4,5]
方法五:使用扩展运算符+concat()
说明:ES6新推出的扩展运算符能对数组进行降维处理(一次降一维),循环判断是否含有数组,进行concat合并。
some()方法:测试数组中是不是至少有1个元素通过了被提供的函数测试(它返回的是一个Boolean类型的值)。
核心:在于反复覆盖arr 再利用some的全为false才能是false的机制去停止while循环
let arr = [1,2,[3,4,[5,[6,7],8],9],10]
function delayering(newArr){
// 核心在于反复覆盖newArr 再利用some的全为false才能是false的机制去停止while循环
while(newArr.some(item => Array.isArray(item))){
// concat 的参数可以是单个值或数组
newArr = [].concat(...newArr)
}
// 单停止while循环再把已经全部扁平化的数组返回回去
return newArr
}
let result = delayering(arr)
console.log(result)
// delayering函数中的newArr变化
// 第一遍while newArr的值是:[1,2,3,4,[5,[6,7],8],9,10]
// 过程:[].concat(1,2,[3,4,[5,[6,7],8],9],10) 合并四个元素到 []数组中
// 第一个元素:1 第二个元素:2 第三个元素:[3,4,[5,[6,7],8],9] 第四个元素:10
// 第二遍while newArr的值是:[1,2,3,4,5,[6,7],8,9,10]
// 过程:[].concat(1,2,3,4,[5,[6,7],8],9,10) 合并七个元素到 []数组中
// 第一个元素:1 第二个元素:2 第三个元素:3 第四个元素:4 第五个元素:[5,[6,7],8] 第六个元素:9 第七个元素:10
// 第三遍while newArr的值是:[1,2,3,4,5,6,7,8,9,10]
// 过程:[].concat(1,2,3,4,5,[6,7],8,9,10) 合并9个元素到 []数组中
// 第一个元素:1 第二个元素:2 第三个元素:3 第四个元素:4 第五个元素:5 第六个元素:[6,7] 第七个元素:8 第八个元素:9 第九个元素:10