交流群:462197261站长百科站长论坛热门标签收藏本站北冥有鱼 互联网前沿资源第一站 助力全行业互联网+
点击这里给我发消息
  • 当前位置:
  • JavaScript之数组扁平化详解

    扁平化

    数组的扁平化,就是将一个嵌套多层的数组 array (嵌套可以是任何层数)转换为只有一层的数组。

    举个例子,假设有个名为 flatten 的函数可以做到数组扁平化,效果就会如下:

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

    知道了效果是什么样的了,我们可以去尝试着写这个 flatten 函数了

    递归

    我们最一开始能想到的莫过于循环数组元素,如果还是一个数组,就递归调用该方法:

    // 方法 1
    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))
    

    toString

    如果数组的元素都是数字,那么我们可以考虑使用 toString 方法,因为:

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

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

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

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

    reduce

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

    // 方法3
    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))
    

    ES6 增加了扩展运算符,用于取出参数对象的所有可遍历属性,拷贝到当前对象之中:

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

    我们用这种方法只可以扁平一层,但是顺着这个方法一直思考,我们可以写出这样的方法:

    // 方法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))
    

    undercore

    那么如何写一个抽象的扁平函数,来方便我们的开发呢,所有又到了我们抄袭 underscore 的时候了~

    在这里直接给出源码和注释,但是要注意,这里的 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, len = value.length;
    while (j < len) 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,就会跳过不进行任何处理,这意味着可以过滤非数组的元素,举个例子:

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

    那么设置 strict 到底有什么用呢?不急,我们先看下 shallow 和 strct 各种值对应的结果:

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

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

    _.flatten

    首先就是 _.flatten:

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

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

    _.union

    接下来是 _.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,就可以跳过传入的非数组的元素。

    // 关于 unique 可以查看《JavaScript专题之数组去重》[](https://github.com/mqyqingfeng/Blog/issues/27)
    function unique(array) {
    return Array.from(new Set(array));
    }
    _.union = function() {
    return unique(flatten(arguments, true, true));
    }
    

    _.difference

    是不是感觉折腾 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;
    })
    }
    

    注意,以上实现的细节并不是完全按照 underscore,具体细节的实现感兴趣可以查看源码。

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持北冥有鱼。

    您可能感兴趣的文章:

    • JS数组扁平化(flat)方法总结详解
    • js嵌套的数组扁平化:将多维数组变成一维数组以及push()与concat()区别的讲解
    • 用javascript实现改变TEXTAREA滚动条和按钮的颜色,以及怎样让滚动条变得扁平
    • js获取对象,数组所有属性键值(key)和对应值(value)的方法示例
    • javascript实现的字符串转换成数组操作示例
    • JS扁平化输出数组的2种方法解析

    广而告之:
    热门推荐:
    解决Pytorch自定义层出现多Variable共享内存错误问题

    错误信息: RuntimeError: in-place operations can be only used on variables that don't share storage with any other variables, but detected that there are 4 objects sharing it 自动求导是很方便, 但是想想, 如果两个Variable共享内存, 再对这个共享的内存的数据进···

    通过javascript获取iframe里的值示例代码

    复制代码 代码如下: <script type="text/javascript" language="javascript"> function CCCC(){ var File_NAME=""; var count=0; if(document.frames("myFrame").document.all.length){ for(var i=0;i<document.all.length;i++){ if(document.frames("myFrame")···

    EasyUI中datagrid在ie下reload失败解决方案

    问题 最近使用EasyUI开发后台系统,测试时发现个奇葩的问题,$('dg').datagrid('reload'); 重新加载表格数据时,ie下一点反应都没有。后来发现其实并不是没有反应,而是浏览器使用了缓存。 解决方案 网上网友总结出来的解决方案有以下几种: 1.在url后加时间戳,使第一次加载···

    Makefile/cmake/node-gyp中区分判断不同平台的方法

    最近用QTK开发一个下载(下载到开发板)工具,同时用到了Makefile/cmake和node-gyp,而且都要针对不同平台做不同的处理。这里做个记录,以备以后有需要时查阅。 Makefile 在Makefile中,可以用OS变量判断当前系统是否是Windows,然后用uname来判断当前系统是MacOS还是其它系统。 ···

    移动网站关键词排名可以从标题与描述下功夫

    相信很多站长在通过seo优化移动站点的过程中发现,移动站点的优化对pc站点的很多方面都非常熟悉。移动台与pc台的显著区别在于界面的大小和移动搜索界面的局限性。移动搜索显示方面可以从标题和描述上下功夫,达到良好的性能。在为网站做标题之前,首先要分析行业竞争力,抓住···

    利用熊掌号主页做关键词排名提升关注转化率

    上回说到自然搜索结果展示高级玩法(搜索结果出图、企业权威问答),而今天继续给大家分享关于熊掌号用户运营沉淀模式-搜索用户里的号主页转化,从而更全面的提升关注转化率。 首先为什么要关注熊掌号主页转化呢? 因为熊掌号的用户是百度搜索积累的生态用户,其运营价值···

    jquery中插件实现自动添加用户的具体代码

    复制代码 代码如下:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  <html xmlns="http://www.w3.org/1999/xhtml">  <head>  <meta http-equiv="Co···

    ASP.NET MVC使用EPPlus,导出数据到Excel中

    好久没写博客了,今天特地来更新一下,今天我们要学习的是如何导出数据到Excel文件中,这里我使用的是免费开源的Epplus组件。 源代码下载:https://github.com/caofangsheng93/ExcelExportInMvc 介绍 这篇文章,介绍的是怎样导出数据到Excel文件中,大多数的后端程序都有报表功···

    web开发设计人员不可不用的在线web工具和应用

    大家可能还记得在过去的文章我们我们曾经介绍我们收集的前端开发人员必备的工具,脚本和资源,在今天的这篇文章中,我们将继续推荐给大家一组我们精挑细选的web开发设计必备的在线工具应用。相信会在web开发和设计的过程中给你带来方便和快捷! 前端开发相关jsfiddle jsfiddle···

    破解.net程序(dll文件)编译和反编译方法

    我只做个简单的小例子,给大家一个思路,吼吼~~~~ 1使用工具 Reflector.exe 用来查看.net代码 这个就不用多说了它是学.net必备神器 Ildasm.exe:用来将dll,exe编译为IL文件 ilasm.exe:用来将IL文件编译回来dll或exe EmEditor文本处理工具这个大家如果没有我这有下载里···