数组扁平化

前言

数组的扁平化,就是将多维数组转换成一维数组。

例如:[1, [2, 3, [4, 5]]] => [1, 2, 3, 4, 5]

接下来我们实现下这个扁平化的函数 flatten

递归

循环判断数组,如果该项类型还是数组,那么就递归调用方法。

let arr = [1, [2, 3, [4, 5]]]

function flatten (arr) {
    let res = []
    for (let i = 0, len = arr.length; i < len; i++) {
        if (Array.isArray(arr[i])) {
            res = res.concat(flatten(arr[i]))
        } else {
            res.push(arr[i])
        }
    }
    return res
}

console.log(flatten(arr)) // [1, 2, 3, 4, 5]

reduce

我们可以使用 reduce 方法来简化上面代码。

function flatten (arr) {
    return arr.reduce(function (acc, cur) {
        return acc.concat(Array.isArray(cur) ? flatten(cur) : cur)
    }, [])
}
console.log(flatten(arr)) // [1, 2, 3, 4, 5]

扩展运算符

function flatten (arr) {
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}
console.log(flatten(arr)) // [1, 2, 3, 4, 5]

因为 [].concat(...arr) 这个只展开一层,所以我们需要循环判断数组类型进行展开。

flat

这是 ES6 提供扁平化数组的方法。

数组的成员有时还是数组,Array.prototype.flat() 用于将嵌套的数组「拉平」,变成一维的数组。该方法返回一个新数组,对原数据没有影响。

flat() 默认只会「拉平」一层,如果想要「拉平」多层的嵌套数组,可以将 flat() 方法的参数写成一个整数,表示想要拉平的层数,默认为1。

如果不管有多少层嵌套,都要转成一维数组,可以用 Infinity 关键字作为参数。

let arr = [1, [2, 3, [4, 5]]]
let flatten = arr.flat(Infinity)
console.log(flatten) // [1, 2, 3, 4, 5]

_.flatMapDeep

_.flatMapDeep() 是 lodash 库提供的数组扁平化方法。源码戳这里在新窗口打开

其中的核心代码贴在下面,我们一起来学习下:

/**
 * 数组扁平化核心方法
 * @param {Array} array 待处理数组
 * @param {number} depth 最大扁平化层次(最大递归深度)默认是 Infinity
 * @param {boolean} [predicate=isFlattenable] 每次迭代调用的函数,而这个函数(isFlattenable)的作用是判断该项是否可以扁平化,依据主要是该项是否是数组或类数组。函数源码地址:https://github.com/lodash/lodash/blob/master/.internal/isFlattenable.js
 * @param {boolean} [isStrict] 是否过滤非数组项
 * @param {Array} [result=[]] 处理结果数组
 * @returns {Array} 返回新的扁平化数组
*/
function baseFlatten (array, depth, predicate, isStrict, result) {
    // => let pred = predicate || isFlattenable
    predicate || (predicate = isFlattenable)
    // => let res = result || []
    result || (result = [])

    if (array == null) {
        return result
    }

    for (const value of array) {
        if (depth > 0 && predicate(value)) {
            if (depth > 1) {
                // 递归地扁平数组(容易受到调用堆栈限制的影响)。
                baseFlatten(value, depth - 1, predicate, isStrict, result)
            } else {
                result.push(...value)
            }
        } else if (!isStrict) {
            result[result.length] = value
        }
    }
    return result
}

结语

本文到这里就结束了。在日常开发中,数组扁平化还是比较常用的,希望看完本文对你有所帮助。

参考文献

JavaScript专题之数组扁平化在新窗口打开