拍平数组的几种方式
Alphawq Arrayflatten
工具方法定义
- 获取变量类型
const getType = (obj, type) =>
Object.prototype.toString.call(obj).replace(/\[object (\w+)]/, '$1') === type
1
2
2
- 判断是否为数组
const isArray = (arr) =>
Array.isArray ? Array.isArray(arr) : getType(arr, 'Array')
1
2
2
# for...of
function flatten(arr) {
let res = []
for (let item of arr) {
res = res.concat(isArray(item) ? flatten(item) : item)
}
return res
}
let arr = [1, [2, 3, [4, 5]]]
flatten(arr) // [1, 2, 3, 4, 5]
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 控制深度
- 利用闭包,新增一个 depth 变量,递归函数每调用一次,就减 1
let flatten = (depth) => {
let _flatten = (arr) => {
if (--depth <= 0) return arr
let res = []
for (let item of arr) {
res = res.concat(isArray(item) ? _flatten(item) : item)
}
return res
}
return _flatten
}
let arr = [1, [2, 3, [4, 5]]]
flatten(2)(arr) // [1, 2, 3, [4, 5]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- 或者不使用闭包,每次都传入这个 depth
let flatten = (arr, depth) => {
if (--depth <= 0) return arr
let res = []
for (let item of arr) {
res = res.concat(isArray(item) ? _flatten(item, depth) : item)
}
return res
}
let arr = [1, [2, 3, [4, 5]]]
flatten(arr, 2) // [1, 2, 3, [4, 5]]
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# reduce
function flatten(arr) {
// 不是数组或数组长度小于等于 1, 则直接返回
if (!isArray(arr) || !arr.length) return arr
return arr.reduce((pre, cur) => {
// 注意concat和push两个方法对原数组的影响
isArray(cur) ? (pre = pre.concat(flatten(cur))) : pre.push(cur)
return pre
}, [])
}
let arr = [1, [2, 3, [4, 5]]]
flatten(arr) // [1, 2, 3, 4, 5]
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 控制深度
let flatten = (depth) => {
return function _flatten(arr) {
// 不是数组或数组长度小于等于 1, 则直接返回
if (--depth <= 0 || !isArray(arr) || arr.length <= 1) return arr
return arr.reduce((pre, cur) => {
// 注意concat和push两个方法对原数组的影响
isArray(cur) ? (pre = pre.concat(_flatten(cur))) : pre.push(cur)
return pre
}, [])
}
}
let arr = [1, [2, 3, [4, 5]]]
flatten(2)(arr) // [1, 2, 3, [4, 5]]
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# generator
function* flatten(arr) {
// 不是数组或数组长度小于等于 1, 则直接返回
if (!isArray(arr) || arr.length <= 1) return arr
for (let item of arr) {
isArray(item) ? yield* flatten(item) : yield item
}
}
let arr = [1, [2, 3, [4, 5]]]
let g = flatten(arr)
console.log([...g]) // [1, 2, 3, 4, 5]
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 控制深度
let flatten = (depth) => {
return function* flatten(arr) {
depth--
// 不是数组或数组长度小于等于 1,则直接返回
if (!isArray(arr) || arr.length <= 1) return arr
for (let item of arr) {
depth <= 0 && isArray(item) ? yield* flatten(item) : yield item
}
}
}
let arr = [1, [2, 3, [4, 5]]]
let g = flatten(2)(arr)
console.log([...g]) // [1, 2, 3, [4, 5]]
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 非递归
以上的方式基本都用到了递归,最后用非递归的方式来实现
非递归的话,就需要自己手动模拟一个栈出来
function flatten(arr) {
if (arr.length <= 1) return arr
let res = []
// pop方法会改变原数组,所以copy一份出来
let stack = arr.slice()
let item
// 不断从栈顶拿出元素,直到栈不为空
while ((item = stack.pop())) {
// 如果是数组,则拍平一层再入栈,否则插入到结果数组的最前端
isArray(item) ? stack.push(...item) : res.unshift(item)
}
return res
}
let arr = [1, [2, 3, [4, 5]]]
flatten(arr) // [1, 2, 3, 4, 5]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 控制深度
function flatten(arr, depth) {
if (arr.length <= 1) return arr
let res = []
// pop方法会改变原数组,所以copy一份出来
let stack = arr.slice()
let item
// 不断从栈顶拿出元素,直到栈不为空
while ((item = stack.pop())) {
// 如果是数组 & --depth >=0 ,则拍平一层再入栈,否则插入到结果数组的最前端
if (isArray(item) && --depth >= 0) {
stack.push(...item)
} else {
res.unshift(item)
}
}
return res
}
let arr = [1, [2, 3, [4, 5]]]
let g = flatten(arr, 2) // [1, 2, 3, [4, 5]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19