#每天都是崭新的一天#再累也要照顾好自己

javascript系列--七种方法实现数组的扁平化

一、前言

数组的扁平化,就是将一个嵌套多层的数组 array (嵌套可以是任何层数)转换为只有一层的数组。在开发中,有时候会遇到如何实现数组的扁平化处理,但是你知道有几种方法来实现这个需求呢?比如举个例子:

比如flatten方法可以实现数组扁平化

var arr = [1, [2, [3, 4]]];
console.log(flatten(arr)) // [1, 2, 3, 4]


二、递归方法

这是最直接和最容易想到的方法。循环数组元素,如果还是一个数组,就递归调用该方法:

var arr = [1, [2, [3, 4]]];
function flatten(arr) {
    var result = [];
    for (var i = 0, len = arr.length; i < len; i++) {
        if (Array.isArray(arr[i])) {
            result = result.concat(flatten(arr[i]))
        }
        else {
            result.push(arr[i])
        }
    }
    return result;
}
console.log(flatten(arr));   // [1,2,3,4]


三、toString方法

如果数组的元素都是数字,name我们可以考虑使用toString方法。

[1, [2, [3, 4]]].toString() // "1,2,3,4"

调用 toString 方法,返回了一个逗号分隔的扁平的字符串,这时候我们再 split,然后转成数字不就可以实现扁平化了吗?

var arr = [1, [2, [3, 4]]];
function flatten(arr) {
    return arr.toString().split(',').map(function(item){
        return +item
    })
}
console.log(flatten(arr));   // [1,2,3,4]

使用的场景却非常有限,如果数组是 [1, '1', 2, '2'] 的话,这种方法就会产生错误的结果。

注意:扁平化不改变原数据,你的结果也显示了,string型的变成了数字


四、reduce方法

对数组进行处理,最终返回一个值,我们就可以考虑使用 reduce 来简化代码

var arr = [1, [2, [3, 4]]];
function flatten(arr) {
    return arr.reduce(function(prev, next){
        return prev.concat(Array.isArray(next) ? flatten(next) : next)
    }, [])
}
console.log(flatten(arr));   // [1,2,3,4]


五、Function.apply.bind([].concat, [])方法

 apply和bind连用,同时绑定调用的方法和调用的主体,只留下一个参数的位置

var flatten = Function.apply.bind([].concat, [])

这个相当于:

var flatten = function(arg) {
  return Function.apply.call([].concat, [], arg)
}

这个是只能扁平化一层,需要借助递归或者遍历。

var arr = [1, [2, [3, 4]]];
function flatten(arr){
    while(arr.some(item => Array.isArray(item))){
	arr = Function.apply.call([].concat, [], arr);
    }
    return arr;
}
flatten(arr);   // [1,2,3,4]



六、ES6的扩展运算符...

扩展运算符,用于取出参数对象中多有可遍历属性,拷贝到当前对象中:

var arr = [1, [2, [3, 4]]];
console.log([].concat(...arr)); // [1, 2, [3, 4]]

用这种方法只可以扁平一层,考虑使用遍历。

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


七、ES6的flat方法

flat将用于将嵌套的数组拉平,变成一维数组。返回一个新数组,不改变原数组。

flat默认参数是1,表示只会拉平一层,如果是嵌套的数组,参数是个数字。

var arr = [1, [2, [3, 4]]];
arr.flat(Infinity);     //[1,2,3,4]

注意:如果原数组有空位,flat方法会跳过空位。


八、undercore里的方法

直接给出源码和注释,但是要注意,这里的 flatten 函数并不是最终的 _.flatten,为了方便多个 API 进行调用,这里对扁平进行了更多的配置。

/**
 * 数组扁平化
 * @param  {Array} input   要处理的数组
 * @param  {boolean} shallow 是否只扁平一层
 * @param  {boolean} strict  是否严格处理元素,下面有解释
 * @param  {Array} output  这是为了方便递归而传递的参数
 * 源码地址:https://github.com/jashkenas/underscore/blob/master/underscore.js#L528
 */
function flatten(input, shallow, strict, output) {

    // 递归使用的时候会用到output
    output = output || [];
    var idx = output.length;

    for (var i = 0, len = input.length; i < len; i++) {

        var value = input[i];
        // 如果是数组,就进行处理
        if (Array.isArray(value)) {
            // 如果是只扁平一层,遍历该数组,依此填入 output
            if (shallow) {
                var j = 0, length = value.length;
                while (j < length) output[idx++] = value[j++];
            }
            // 如果是全部扁平就递归,传入已经处理的 output,递归中接着处理 output
            else {
                flatten(value, shallow, strict, output);
                idx = output.length;
            }
        }
        // 不是数组,根据 strict 的值判断是跳过不处理还是放入 output
        else if (!strict){
            output[idx++] = value;
        }
    }

    return output;

}

说明: strict,在代码里我们可以看出,当遍历数组元素时,如果元素不是数组,就会对 strict 取反的结果进行判断,如果设置 strict 为 true,就会跳过不进行任何处理,这意味着可以过滤非数组的元素。

ar arr = [1, 2, [3, 4]];
console.log(flatten(arr, true, true)); // [3, 4]

设置 strict 到底有什么用呢?

shallow true + strict false :正常扁平一层
shallow false + strict false :正常扁平所有层
shallow true + strict true :去掉非数组元素
shallow false + strict true : 返回一个[]

看看 underscore 中哪些方法调用了 flatten 这个基本函数:

1、_.flatten方法

_.flatten = function(array, shallow) {
    return flatten(array, shallow, false);
};

在正常的扁平中,我们并不需要去掉非数组元素。


2、_.union方法

这个函数,传入多个数组,返回传入数组的并集。

看个栗子:

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]

如果传入的参数并不是数组,就会将该参数跳过:

_.union([1, 2, 3], [101, 2, 1, 10], 4, 5);
=> [1, 2, 3, 101, 10]

为了实现这个效果,我们将传入的所有数组扁平化,然后去重。这时候设置strict为true,就可以跳过传入的非数组的元素。

function unique(array) {
   return Array.from(new Set(array));
}

_.union = function() {
    return unique(flatten(arguments, true, true));
}


3、_.defferernce方法

是不是感觉折腾 strict 有点用处了,我们再看一个 _.difference:

语法:

_.difference(array, *others)

作用是:取出来自array数组,并且不存在与多个other数组的元素。注意:跟 _.union 一样,都会排除掉不是数组的元素。

看个栗子:

_.difference([1, 2, 3, 4, 5], [5, 2, 10], [4], 3);
=> [1, 3]

实现方法也很简单,扁平化others的数组,筛选出array中不在扁平化数组中的值。

function difference(array, ...rest) {

    rest = flatten(rest, true, true);

    return array.filter(function(item){
        return rest.indexOf(item) === -1;
    })
}

如果有兴趣的可以看一下源码:传送门(https://github.com/jashkenas/underscore/blob/master/underscore.js#L528


九、总结

javascript系列--多种方法实现数组的扁平化。包括:常用的递归,toString+split(','),递归+reduce(归纳),遍历+Function.apply.bind([].concat, [], arr),ES6的扩展运算符[].concat(...arr),ES6的flat(),undercore里的_.flatten方法。


【注:我是saucxs,也叫songEagle,松宝写代码,文章首发于sau交流学习社区 https://www.mwcxs.top ,关注我们每天阅读更多精彩内容】


感谢你的阅读,本文由 sau交流学习社区 版权所有。
如若转载,请注明出处:sau交流学习社区-power by saucxs(程新松)(/page/763.html)
交流咨询
    官方QQ群
    群号663940201,欢迎加入!
    sau交流学习社区交流群

微信群
欢迎加入微信群
微信公众号
欢迎关注微信公众号

图文推荐

微信群
saucxs聊天机器人
saucxs
hi ,欢迎来到sau交流学习社区,欢迎与我聊天,问我问题哦!
您正在使用的浏览器是,不在支持范围内!
为了您的正常使用与展示,推荐使用Chrome浏览器68以上版本
支持浏览器:
火狐浏览器最新版
Safari浏览器最新版
Edge浏览器最新版
IE浏览器10,11