项目实战 | Js 数据结构转化处理

452 阅读4分钟

这是我参与8月更文挑战的第 27 天,活动详情查看:8月更文挑战

前言

在本示例中,用到了 js 的 3 种结构,Object, Array, Set,用 Object 替代 Map 是个人觉得 Map 的 API 记不住不好使,使用起来也没有 Object 那么丝滑,当然,这 2 中数据结构肯定是有区别的,我这里就不做讲解了,直接搬运了他人的文章 JS 项目中究竟应该使用 Object 还是 Map? (作者居然是 掘金开发者社区??小尴尬)

功能需求

页面访问一个接口,需要拿到一大堆的数据分析,同时需要将原始的数据导入的 Excel 供客户查阅

因为需要传递原始的数据到页面上,而且数据处理的维度较多,使用 java 操作的话会显得比较啰嗦,于是决定将处理的逻辑转移到页面上。因为这个表是逻辑关联的,涉及到的一些外键表数据,就需要后台处理一下同步传递到页面上,后续数据需要关联时再调用、转化

还有一个优点就是,数据处理方式的如需要变更,可以直接在页面上调整,不用再通过后台配合调整

后台数据返回结构

示例的列表数据如下,已省略其余的字段内容,接受到的后台数据类似于 data = [{'line': '101', 'grade': 'A'}, ....],一个单纯的 List<Object> 结构

线别(line)	等级(grade)
101		A
101		A
101		B
102		A
102		C
102		C

其中一个统计功能

需求

根据线别来统计,各个等级共有多少

分析

我们需要记录下来,这一串的数据里,涉及到了哪些线别,对应的线别下又有哪些等级,这些等级的数量又是多少

我们直接使用对象套对象的方式,得到类似于这样的数据结构 obj = { 101: { A: 1, B: 2}, ...}

let obj = {};
data.forEach(n => {
  data[n.line] = data[n.line] || {};	// 初始化具体的线别,不存在的情况下给默认值
	let num = data[n.line][n.grade] || 0;	// 初始化具体的等级,不存在,给 0
	data[n.line][n.grade] = num + 1;	// 对应等级的计数,+1,不太建议使用 ++num,这种操作会变更原数据
})

下面就是最后处理好的结果

obj = {
	101: {
		A: 2,
		B: 1
	},
	102: {
		A: 1,
		C: 2
	}
}

初步的渲染效果

根据处理好后的数据,我们直接渲染到 table 里的话,大概效果如下

线别等级及数量
101A: 2, B: 1
102A: 1, C: 2

这可能看不出什么,我贴一个更贴近实际的预览效果

线别等级及数量
101A: 200, B: 100, D: 2
102A: 10, C: 2
103B: 200, D: 100
104C: 12

现在再来看一下数据的展示,问题就非常明显了!因为线别他们具备的等级可能是不一样的!我们没法直接渲染为标准的表格数据!无法直观对比,横向看还好,纵向对比,根本对比不了相同等级的数据!

优化

直接考虑一个动态处理,我们将这批数据里涉及到的等级,全部提取出来,改进上一步的操作

我们先对 data 进行数据调整,用 set 去重,用 ... 扩展为数组数据,再排序(这也就是我为什么倾向 js 处理数据,简洁!)

let grades = [...new Set(data.map(n => n.grade))].sort();

现在,我们改造上一步的统计

let obj = {};
gradeObj = {};
grades.forEach(g => gradeObj[g] = 0);	// 获得一个处理好的 grade object,后面使用时通过克隆的方式
data.forEach(n => {
  data[n.line] = data[n.line] || Object.assign({}, gradeObj);	// 初始化具体的线别,不存在的情况下给默认值
	let num = data[n.line][n.grade] || 0;	// 初始化具体的等级,不存在给 0
	data[n.line][n.grade] = num + 1;	// 对应等级的计数,+1,不太建议使用 ++num,这种操作会变更原数据
})

现在,每个线别都有一样的等级结构了,我们直接就能将表格效果优化为如下

线别ABC
101210
102102

这样的话,我们能非常直观的看出这些等级数量的横向对比,纵向对比,比上一版好了起码一个档次