返回顶部
首页 > 资讯 > 精选 >怎么在前端使用JS进行分类
  • 784
分享到

怎么在前端使用JS进行分类

2023-07-05 21:07:52 784人浏览 八月长安
摘要

今天小编给大家分享一下怎么在前端使用js进行分类的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。提出问题不扯远了,先来看问题。

今天小编给大家分享一下怎么在前端使用js进行分类的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    提出问题

    不扯远了,先来看问题。根据下面的样例数据,要求得到

    • 先按业务,再按部门分组的数据;

    • 不按部门,直接按业务分别统计每年的数据

    [  {    name: "部门1",    businesses: [      {        name: "产品销售",        years: [          { name: "2021", value: 132 }, { name: "2022", value: 183 }, { name: "2023", value: 207 }        ]      },      {        name: "原料采购",        years: [          { name: "2021", value: 143 }, { name: "2022", value: 121 }, { name: "2023", value: 120 }        ]      }    ]  },  {    name: "部门2",    businesses: [      {        name: "产品销售",        years: [          { name: "2021", value: 230 }, { name: "2022", value: 112 }, { name: "2023", value: 288 }        ]      },      {        name: "原料采购",        years: [          { name: "2021", value: 168 }, { name: "2022", value: 203 }, { name: "2023", value: 115 }        ]      }    ]  },  {    name: "部门3",    businesses: [      {        name: "产品销售",        years: [          { name: "2021", value: 279 }, { name: "2022", value: 163 }, { name: "2023", value: 271 }        ]      },      {        name: "原料采购",        years: [          { name: "2021", value: 129 }, { name: "2022", value: 121 }, { name: "2023", value: 226 }        ]      }    ]  }];

    这个数据,如果用金山文档的轻维表(飞书多维表类似)来查看,会更直观

    原数据(按部门再按业务)的轻维表呈现

    怎么在前端使用JS进行分类

    按业务再按部门分组的轻维表呈现

    怎么在前端使用JS进行分类

    按业务按年统计的轻维表呈现

    怎么在前端使用JS进行分类

    展平多级数据

    原数据按部门再按业务进行了两级分类,所以它不是简单的二维表(行/列)数据,而是在二维表的基础上增加了两个维度(部门/业务)。从要求来看,我们需要的是从另外的维度(业务/部门,业务/年度)来进行处理。所以需要先把这些数据降维展开成可以重新划分维度的程度,也就是二维表。

    JS 中二维表的表示方法挺多,行对象集合是最常见的一种,这里我们也就采用这种表示方法。

    还有一种常见的方式是列集合+行集合,其中行集合可以是对象表示(字段名对应)也可以是数组表示(索引号对应)。不过这种表示一会是用在 UI 中。单纯数据处理用行对象集合就够了,不需要单独的列信息。

    观察原数据的每一级,发现名称都命名为 name,但是子集命名各不相同,层级有限。由于对每一层需要去处理名称到列(对象属性名)的转换,也需要对不同名称的子集进行进一步处理,各层级之间缺乏显而易见的共性,不太适合递归的方式来处理。所以我们定做一个展开函数。

    下面是对原数据量身定做的展开函数,展开后会得到一个包含部门 (dept)、业务 (business)、年份 (year)、数值 (value) 四个属性的对象集合。

    function flatBusinesses(list) {    return list.flatMap(({ name: dept, businesses }) => {        return businesses.flatMap(({ name: business, years }) => {            return years.map(({ name: year, value }) => ({                dept,                business,                year,                value            }));        });    });}


    晋级:如果想用递归该怎么处理?

    并不是多级展开就一定会用到递归。比如规则的数组结构,比如规则的树结构,是可以使用递归遍历展开的。但是像这个案例的数据,每一层的子级属性名称都不同,层级有限,需要逐级处理。

    如果实在想用递归的话,也可以通过一个参数来定义每一级的处理规则。以这个例子来说,每一级要处理两件事:① 找到子级节点属性名;② 将 name 处理成适当的名称用在展开的数据中。

    function flatMultiLevelList(list, rules) {    return flatList(list, 0);    function flatList(list, level) {        const rule = rules[level];        if (!rule) { return [{}]; }        // 取得 field(子级属性名)和 convert(属性处理器)        // 如果没有 convert 则指定一个默认的 it => it,即不做转换        const { field, convert = it => it } = rule;        if (field) {            // 如果存在子级,则继续 flatMap,展平。            // ❶ { fff, ...others } 可以将 fff 属性从原对象中剥离出来            // ❷ { [feild]: nodes } 解构可以将 field 的值所指向的属性取出来赋予一个叫 nodes 的变量            return list.flatMap(({ [field]: nodes, ...props }) => {                return flatList(nodes, level + 1).map(it => ({ ...convert(props), ...it }));            });        } else {            // 如果不存在子级,只需要对当前节点进行转换,直接返回即可            return list.map(it => convert(it));        }    }}

    展开后会拿到这样的数据(假设赋值变量 table

    [    { "dept": "部门1", "business": "产品销售", "year": 2021, "value": 132 },    { "dept": "部门1", "business": "产品销售", "year": 2022, "value": 183 },    { "dept": "部门1", "business": "产品销售", "year": 2023, "value": 207 },    { "dept": "部门1", "business": "原料采购", "year": 2021, "value": 143 },    { "dept": "部门1", "business": "原料采购", "year": 2022, "value": 121 },    { "dept": "部门1", "business": "原料采购", "year": 2023, "value": 120 },    { "dept": "部门2", "business": "产品销售", "year": 2021, "value": 230 },    { "dept": "部门2", "business": "产品销售", "year": 2022, "value": 112 },    ...]

    拿到二维表之后,某些需要的数据或视图就可以通过电子表格来获得。比如问题一中需要的统计数据,使用电子表格的透视图功能就能实现,而金山文档的轻维表,或者飞书的多维表可以实现得更容易。不过我们现在需要用代码来实现。

    分类及分类汇总

    第一个问题的需求是分类和分类汇总。说到分类,那首先想到的肯定是 group 操作。很可惜原生 JS 不支持 group,如果想用现成的,可以考虑 Lodash,要自己写一个倒也不难。group 操作前面提到的展开操作的逆操作。

    function groupBy(list, key) {    // 这里简单地兼容一下传入 key 值和 keyGetter 的情况    const geTKEy = typeof key === "function" ? key : it => it[key];    return list.reduce(        (groups, it) => {            (groups[getKey(it)] ??= []).push(it);            return groups;        },        {}  // 空对象作为初始 groups    );}

    按业务再按部门分组

    有了 groupBy,可以先按业务进行分组

    // 前面假设展平的数据存放在变量 table 中const groups = groupBy(table, "dept");

    现在我们拿到的 byDept 是一个 JS 对象(注意不是数组哦),其键是部门名称,值是一个数组,包含该部门下的所有数据。接下来进行第二层分组,是需要对 byDept 的每一个“值”进行分组处理。

    for (const key in groups) {    const list = groups[key];    groups[key] = groupBy(list, "business");}

    处理之后的 groups 长得像这样

    {    "产品销售": {        "部门1": [            { dept: "部门1", business: "产品销售", year: "2021", value: 132 },            ...        ],        "部门2": [            { dept: "部门2", business: "产品销售", year: "2021", value: 230 },            ...        ],        "部门3": ...    },    "原料采购": ...}

    结果是拿到了,但是和符合原始的数据规范(原始层级每层是用 name 属性作为字段名,子级命名各不相同)所以还需要做一次转换。比如第一层的转换是这样:

    const converted = Object.entries(groups)    .map(([name, depts]) => ({ name, depts }));

    它会把第一层(对象)处理成数组,每个元素包含 name 和 depts 两个属性,name 属性是名称,depts 则是按部门分组的结果(目前还是对象)。那么第二、三层转换也类似。把前面的分组和后面的转换合并起来,是这样

    const result1 = Object.entries(groupBy(table, "business"))    .map(([name, list]) => ({        name,        depts: Object.entries(groupBy(list, "dept"))            .map(([name, list]) => ({                name,                years: list.map(({ year: name, value }) => ({ name, value }))            }))    }));

    得到最终结果

    [  {    name: "产品销售",    depts: [      {        name: "部门1",        years: [{ name: "2021", value: 132 }, { name: "2022", value: 183 }, { name: "2023", value: 207 }]      },      {        name: "部门2",        years: [{ name: "2021", value: 230 }, { name: "2022", value: 112 }, { name: "2023", value: 288 }]      },      {        name: "部门3",        years: [{ name: "2021", value: 279 }, { name: "2022", value: 163 }, { name: "2023", value: 271 }]      }    ]  },  ...]

    按业务分组再按年统计

    对于第一个问题的第二个需求,要按年统计业务(忽略部门),处理方法与上面的方法类型。第二层分组改为按年份,而不是按部门;同时第二层的数组转换时不再转换第三层的数据,而是对第三层数据进行汇总。

    const result2 = Object.entries(groupBy(table, "business"))    .map(([name, list]) => ({        name,        years: Object.entries(groupBy(list, "year"))//      ^^^^^                               ^^^^^^ 按年分组            .map(([name, list]) => ({                name,                value: list.reduce((sum, { value }) => sum + value, 0)//              ^^^^^ 直接取值,使用 reduce 汇总            }))    }));

    结果(用前面做的轻维表统计来核对一下,完全正确)

    [  {    name: "产品销售",    years: [{ name: "2021", value: 641 }, { name: "2022", value: 458 }, { name: "2023", value: 766 }]  },  {    name: "原料采购",    years: [{ name: "2021", value: 440 }, { name: "2022", value: 445 }, { name: "2023", value: 461 }]  }]

    如果用 Lodash 会怎么写

    用 Lodash 来处理代码结构看起来更清晰一些,但代码量不见得少。

    展开的部分用 Lodash 和使用原生方法没什么区别,都是使用 flatMap。Lodash 提供的 flatMapDeep 可以用来展开纯粹的多级数组,但在这里不适用,因为每一级都不是单纯的展开,而是要进行单独的映射处理。Lodash 的 flatMapDeep 更像是原生的 map().flat(Number.MAX_SAFE_INTEGER)

    const result1 = _(table)    // groupBy 的结果是一个对象,属性名是组名,属性值是组内数据列表。    .groupBy("business")    // 第一种处理值集的方法,先把值处理了 (mapValues),再来处理键值对 (map)    .mapValues(depts => _(depts)        .groupBy("dept")        // 第二种处理值集的方法,处理键值对的时候,同时处理值集合        .map((values, name) => ({            name,            years: values.map(({ year: name, value }) => ({ name, value }))        }))        .value()    )    .map((depts, name) => ({ name, depts }))    .value();
    const result2 = _(table).groupBy("business")    .map((list, name) => ({        name,        years: _(list).groupBy("year")            .map((list, name) => ({                name,                value: _.sumBy(list, "value")            }))            .value()    }))    .value();

    小结

    如果需要对某个数据进行分类或者分类汇总,首先得拿到这个数据的二维表,也就是完全展开的数据列表。多数情况下从后端拿到的数据都是二维表,毕竟关系型数据库逻辑结构是表存储。接下来所谓的“分类”其实就是分组操作,而“汇总”就是把分类后的子列表拿来进行聚合计算(计数、合计、平均、最大/小等都是聚合计算),得到最终的结果。

    以上就是“怎么在前端使用JS进行分类”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

    --结束END--

    本文标题: 怎么在前端使用JS进行分类

    本文链接: https://lsjlt.com/news/355518.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    猜你喜欢
    • 怎么在前端使用JS进行分类
      今天小编给大家分享一下怎么在前端使用JS进行分类的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。提出问题不扯远了,先来看问题。...
      99+
      2023-07-05
    • 一文详解如何在前端使用JS进行分类汇总
      目录前言提出问题原数据(按部门再按业务)的轻维表呈现按业务再按部门分组的轻维表呈现按业务按年统计的轻维表呈现展平多级数据晋级:如果想用递归该怎么处理?分类及分类汇总按业务再按部门分组...
      99+
      2023-05-14
      js 分类 javascript分类 js分类汇总
    • Vue怎么使用MD5对前后端进行加密
      这篇文章主要介绍了Vue怎么使用MD5对前后端进行加密的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue怎么使用MD5对前后端进行加密文章都会有所收获,下面我们一起来看看吧。前端在public下面新建一个MD...
      99+
      2023-06-29
    • 在 JS 中怎么使用 Ajax 来进行请求
      本篇内容介绍了“在 JS 中怎么使用 Ajax 来进行请求”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1...
      99+
      2024-04-02
    • python怎么使用tensorflow进行图像分类
      本文小编为大家详细介绍“python怎么使用tensorflow进行图像分类”,内容详细,步骤清晰,细节处理妥当,希望这篇“python怎么使用tensorflow进行图像分类”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习...
      99+
      2023-07-02
    • python中怎么使用Keras进行简单分类
      本篇内容介绍了“python中怎么使用Keras进行简单分类”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Keras中分类的重要函数1、np...
      99+
      2023-06-30
    • graphQL怎么在前端vue中使用
      这篇文章主要介绍“graphQL怎么在前端vue中使用”,在日常操作中,相信很多人在graphQL怎么在前端vue中使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”graphQL怎么在前端vue中使用”的疑...
      99+
      2023-07-05
    • 前端怎么用post的方式进行eventSource请求
      本篇内容主要讲解“前端怎么用post的方式进行eventSource请求”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“前端怎么用post的方式进行eventSource请求”吧!1.eventS...
      99+
      2023-07-06
    • vue中使用jeecg进行前后端联调方式
      目录vue使用jeecg进行前后端联调vue jeecg表格对数据的处理自定义vue使用jeecg进行前后端联调 最近项目中总是用jeecg来进行系统管理端的操作,因为jeecg可以...
      99+
      2024-04-02
    • 怎么使用Mongodb进行分析
      要使用Mongodb进行分析,需要按照以下步骤进行操作:1. 安装Mongodb数据库:首先,需要安装Mongodb数据库,并将其设...
      99+
      2023-08-23
      Mongodb
    • 前端怎么对接口数据进行加密
      在前端中使用AES对接口数据进行加密的方法前端代码如下:var aesUtil = {//获取key,genKey : function (length = 16) {let random = "ABCDEFGHIJKLMNOPQRSTUV...
      99+
      2024-04-02
    • NoSQL数据库怎么与前端进行交互
      NoSQL数据库与前端可以通过以下几种方式进行交互: RESTful API:通过RESTful API调用数据库的接口,前端可...
      99+
      2024-05-07
      NoSQL
    • Vue前端怎么实现与后端进行数据交互
      这篇文章主要介绍了Vue前端怎么实现与后端进行数据交互的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue前端怎么实现与后端进行数据交互文章都会有所收获,下面我们一起来看看吧。Vue前端与后端数据交互安装npm...
      99+
      2023-06-29
    • 怎么用Python进行系统聚类分析
      怎么用Python进行系统聚类分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。在进行机器学习时,我们往往要对数据进行聚类分析,聚类,说白了就是把相似的样品点/...
      99+
      2023-06-16
    • axios和SpringBoot前端怎么调用后端接口进行数据交互
      这篇文章主要介绍“axios和SpringBoot前端怎么调用后端接口进行数据交互”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“axios和SpringBoot前端怎么调用后端接口进行数据交互”文章...
      99+
      2023-07-05
    • 怎么使用Mahout进行空间聚类
      Mahout是一个用于大规模机器学习的框架,其中包含了许多用于空间聚类的算法。要使用Mahout进行空间聚类,可以按照以下步骤进行:...
      99+
      2024-05-22
      Mahout
    • Vue使用MD5对前后端进行加密的实现
      目录前端后端前后端分离的项目,遇到了对密码进行加密的情况,在前端或者是在后端加密都是可以的。但是从用户数据的安全性来讲,前后端是都需要进行加密的。后端不加密的话,数据库中存储明文密码...
      99+
      2024-04-02
    • git前后端分离怎么用
      随着前端技术的繁荣发展,前端领域出现了越来越多的框架和技术,前后端分离也成为了现阶段 web 开发的一种趋势。其中,git 的使用对于前后端分离的管理起到了至关重要的作用。本文将介绍 git 前后端分离的使用方法。一、前后端分离的基本概念前...
      99+
      2023-10-22
    • Python怎么使用Spacy进行分词
      这篇文章主要介绍“Python怎么使用Spacy进行分词”,在日常操作中,相信很多人在Python怎么使用Spacy进行分词问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python怎么使用Spacy进行分词...
      99+
      2023-06-30
    • JS前端使用canvas实现扩展物体类和事件派发
      目录前言FabricImage 图片类事件派发小结前言 虽然我们讲了这么多个章节,但其实目前为止就只有一个 Rect 类能用,略显单调。于是乎,为了让整个画布稍微生动一些,这个章节我...
      99+
      2022-11-13
      canvas扩展物体类事件派发 前端canvas扩展物体类
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作