资讯专栏INFORMATION COLUMN

JavaScript 数组分组的实现

Coly / 1788人阅读

摘要:今天回答了的问题生产嵌套数组也就是对数组分组更好的写法。实现像这种,目标数组长度和原数组长度不一致的情况,函数式写法很容易想到函数。小结数组分组是一个很简单的问题,有很多种方法来处理。

今天回答了 @_bleach 的问题:JS生产嵌套数组(也就是对数组分组)更好的写法。回答的过程中对 lodash _.chunk() 产生了好奇,所以分析了一下它的源码,再加上我自己的解决方案,收集了如下一些方案,分享给大家

按惯例,我还是使用 es6 语法,在 Node7 中实验通过

数据和参数和期望结果
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
const groupByNum = 3;

RxJS

因为最近在学习 RxJs,所以顺手做了个 RxJs 解决方案。但这不是重点。不了解或者很了解 RxJs 的请忽略。

RxJava 很火,其实 ReactiveX 有很多种语言的实现,JavaScript 的实例就是 RxJs,建议学习的同学直接上 5.0 Beta。不过 RxJs 主要用于异步流处理,所以需要通过回调函数来使用结果。

const Rx = require("rxjs");
const out = Rx.Observable.from(data)
    .bufferCount(groupByNum)
    .toArray()
    .do((result) => {
        console.log(result)
    })
    .subscribe();

上面的 do() 一句可以直接写成 do(console.log),写成现在这样的目的是为了让大家看到计算结果在哪。

_.chunk() 实现

lodash 提供了大量数据处理的方法,_.chunk() 专为分组而生

const _ = require("lodash");
const result = _.chunk(data, groupByNum);
_.chunk() 的源码

在 node 环境也,通过 npm 安装 lodash 之后就能在 node_modules/lodash 目录下找到源码文件 chunk.js

npm install lodash

所以完整的源码不贴了,只看下关键的那一句

  while (index < length) {
    result[resIndex++] = baseSlice(array, index, (index += size));
  }

baseSlice() 是 lodash 对 Array.prototype.slice() 的兼容性实现,可以直接当 slice() 来看。看了这个源码,我有了函数式写法的思路,后面通过 slice() + map() 实现部分详述。

reduce() 实现

像这种,目标数组长度和原数组长度不一致的情况,函数式写法很容易想到 reduce() 函数。只可惜单纯的 reduce() 做不出来(在 data.length 不能被 groupByNum 整除的时候)

function groupArray(data, cols) {
    const r = data.reduce((r, t) => {
        r.current.push(t);
        if (r.current.length === cols) {
            r.list.push(r.current);
            r.current = [];
        }
        return r;
    }, { list: [], current: [] });

    if (r.current.length) {
        r.list.push(r.current);
    }

    return r.list;
}

const result = groupArray(data, groupByNum);

reduce() 的初始化对象是 { list: [], current: [] },其中 list 是要得计算出来的结果,而 current 是中间变量,用于生成每个组。

最后由于不有保证 data.length 一定被 groupByNum 整除,所以可能会有一个未完成的 current 没被 push 到 list 当中,所以专门进行了一个判断和处理。因此不能写成函数式写法,有些遗憾。

forEach() 实现

既然不能用函数式写法,那 forEach() 或者 for ... of 实现就会更容易理解一些。

function groupArray(data, cols) {
    const list = [];
    let current = [];

    // for (t of data) {
    data.forEach(t => {
        current.push(t);
        if (current.length === cols) {
            list.push(current);
            current = [];
        }
    });
    // }    // for (t of data)

    if (current.length) {
        list.push(current);
    }
    return list;
}
slice() + map() 实现

看到了 _.chunk() 的源码,让我产生了函数式写法的灵感,相比上面的解决方案,更难于理解,不过语法看起来很酷

const result = Array.apply(null, {
    length: Math.ceil(data.length / groupByNum)
}).map((x, i) => {
    return data.slice(i * groupByNum, (i + 1) * groupByNum);
});

Array.apply() 是为了生成一个长度为 Math.ceil(data.length / groupByNum) 的数组作为 map() 的源,map() 不需要这个源的数据,只需要这个源每个数组的 index

Math.ceil() 用于保证在除法计算有余数的时候对商 +1,即循环次数 +1。

然后在算得的循环次数中,通过 slice 返回每一段结果,通过 map() 映射出来,最终生成需要的结果。

小结

数组分组是一个很简单的问题,有很多种方法来处理。本文并不是想告诉大家如何处理这个问题,而是将我处理问题的思路分享出来,希望能对处理各种数据问题带来一点点启发。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80868.html

相关文章

  • JavaScript 实现数组更多高阶函数

    摘要:实现数组更多的高阶函数吾辈的博客原文场景虽说人人平等,但有些人更加平等。若是有一篇适合萌新阅读的自己实现数组更多操作的文章,情况或许会发生一些变化。类似于的初始值,但它是一个函数,避免初始值在所有分组中进行累加。 JavaScript 实现数组更多的高阶函数 吾辈的博客原文: https://blog.rxliuli.com/p/fc... 场景 虽说人人平等,但有些人更加平等。 为...

    aervon 评论0 收藏0
  • JavaScript那些坑

    摘要:序列化为字符串之后它的各个属性已经被解除了引用,重新相当于创建了一个新的对象。类似于的,的命令行终端。基本思路函数的使用以及协议。 多行注释的陷阱 由于正则表达式字面量的存在,多行注释可能会产生陷阱,例如以下程序将抛出错误: /* var a = /h*/.test(hello); */ 正则结束前的那个星号将被解析为注释结束符,从而.被认为是不合法的.所以尽量避免使用多行注释 整型 ...

    ivyzhang 评论0 收藏0
  • 排序算法Javascript实现

    摘要:排序加了的插入排序。分别以索引数为的元素为起点,将其看做不同的组,,,为一组,,为一组依次分组,按照组为单位进行插入排序。各组都已经插入排序一轮过后,将除以向下取整,再进行分组并将各组分别进行插入排序,直到为。 1.冒泡排序: 比较相邻的两个数,如果前一个数大于后一个数,就将这两个数换位置。每一次遍历都会将本次遍历最大的数冒泡到最后。为了将n个数排好序,需要n-1次遍历。 如果某次遍历...

    fredshare 评论0 收藏0
  • javascript 正则命名分组

    摘要:早已实现了正则命名分组提案,只是我们很少使用,本文将介绍的正则命名分组。所有这些问题,都可以通过正则命名分组来解决。该名称必须是合法的标识符。 前言 以往我们只是习惯于通过数组下标来访问正则匹配到的分组,但分组达到4、5个时,标识起来就会非常麻烦。V8早已实现了正则命名分组提案,只是我们很少使用,本文将介绍JS的正则命名分组。 以往的做法 假设要使用正则匹配一个日期的年月日,以往我们会...

    Galence 评论0 收藏0
  • 玩转javascript RegExp对象

    摘要:玩转对象中的正则表达式的正则表达式语法极大地借鉴了另一种脚本语言的正则表达式语法对象是的一个内置对象,与,类似。创建对象可通过构造函数创建。当要根据用户输入来构造正则表达式时,必须采用构造函数方式。如与被看做相同的字符模式。 玩转javascript RegExp对象 js中的正则表达式 js的正则表达式语法极大地借鉴了另一种脚本语言Perl的正则表达式语法.RegExp对象是js的一...

    alexnevsky 评论0 收藏0

发表评论

0条评论

Coly

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<