JS对大量数据进行多重过滤的方法


Posted in Javascript onNovember 04, 2016

前言

主要的需求是前端通过 Ajax 从后端取得了大量的数据,需要根据一些条件过滤,首先过滤的方法是这样的:

class Filter {
 filterA(s) {
 let data = this.filterData || this.data;
 this.filterData = data.filter(m => m.a === s);
 }
 
 filterB(s) {
 let data = this.filterData || this.data;
 this.filterData = data.filter(m => m.b === s);
 }
}

现在迷糊了,觉得这样处理数据不对,但是又不知道该怎么处理。

发现问题

问题就在过滤上,这样固然可以实现多重过滤(先调用 filterA() 再调用 filterB() 就可以实现),但是这个过滤是不可逆的。

假如过滤过程是这样:

f.filterA("a1");
f.filterB("b1");
f.filterA("a2");

本来是希望按 "a1" 和 "b1" 过滤了数据之后,再修改第一个条件为 "a2",但结果却成了空集。

解决问题

发现了问题,就针对性的解决。这个问题既然是因为过滤过程不可逆造成的,那每次都直接从 this.data 开始过滤,而不是从 this.filterData 开始过滤,就能解决问题。如果要这样做,就需要将选择的过滤条件先记录下来。

记录过滤条件

用一个列表记录过滤条件当然是可行的,但是注意对同一个条件的两次过滤是互斥的,只能保留最后一个,所以应该用 HashMap 更为合适。

class Filter {
 constructor() {
 this.filters = {};
 }

 set(key, filter) {
 this.filters[key] = filter;
 }

 getFilters() {
 return Object.keys(this.filters).map(key => this.filters[key]);
 }
}

这种情况下,像上面的过程表示为

f.set("A", m => m.a === "a1");
f.set("B", m => m.b === "b1");
f.set("A", m => m.a === "a1");

let filters = f.getFilters(); // length === 2;

上面第 3 句设置的 filter 覆盖了第 1 句设置的那个。现在再用最后取得的 filters 依次来过滤原数据 this.data,就能得到正确的结果。

有人会觉得 getFilters() 返回的列表不是按 set 的顺序的——的确,这是 HashMap 的特点,无序。不过对于简单条件的判断,不管谁先谁后,结果是一样的。但是对于一些复合条件判断,就可能会有影响。

确实需要的话,可以通过 array 代替 map 来解决一下顺序的问题,但这样查找效率会降低(线性查找)。如果还想解决查找效率的问题,可以用 array + map 来处理。这里就不多说了。

过滤

实际上在使用的时候,每次都 getFilter() 再用一个循环来处理确实比较慢。既然 data 都封装成 Filter 中,可以考虑直接给一个 filter() 方法来送货过滤接口。

class Filter {
 filter() {
 let data = this.data;
 for (let f of this.getFilters()) {
  data = data.filter(f);
 }
 return data;
 }
}

不过这样我觉得效率不太好,尤其是对大量数据的时候。不妨利用一下 lodash 的延迟处理过程。

利用 lodash 的延迟处理

filter() {
 let chain = _(this.data);
 for (let f of this.getFilters()) {
 chain = chain.filter(f);
 }
 return chain.value();
}

lodash 在数据大于 200 的时候会启用延迟处理过程,也就是说,它会处理成一个循环中依次调用每一个 filter,而不是对每一个 filter 进行一次循环。

延迟处理和非延迟处理通过下图可以看出来区别。非延迟处理总共会进行 n(这里 n = 3) 次大循环,产生 n - 1 个中间结果。而延迟处理只会进行一次大循环,没有中间结果产生。

JS对大量数据进行多重过滤的方法

不过说实在的,我不太喜欢为了一点小事多加载一个库,所以干脆自己做个简单的实现

自己实现延迟处理

filter() {
 const filters = this.getFilters();
 return data.filter(m => {
 for (let f of filters) {
  // 如果某个 filter 已经把它过滤掉了,也不用再用后面的 filter 来判断了
  if (!f(m)) {
  return false;
  }
 }
 return true;
 });
}

里面的 for 循环还可以用 Array.prototype.every 来简化:

filter() {
 const filters = this.getFilters();
 return data.filter(m => {
 return filters.every(f => f(m));
 });
}

数据过滤其实并不是多复杂的事情,只要把思路理清楚,搞明白什么数据是需要保留的,什么数据是临时(中间过程)的,什么数据是最终结果……利用 Array.prototype 中的相关方法,或者诸如 lodash 之类的工具,很容易就处理出来了。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能有所帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
js中的数组Array定义与sort方法使用示例
Aug 29 Javascript
JavaScript中为什么null==0为false而null大于=0为true(个人研究)
Sep 16 Javascript
JavaScript中的Math.SQRT1_2属性使用简介
Jun 14 Javascript
JS简单获取客户端IP地址的方法【调用搜狐接口】
Sep 05 Javascript
js本地图片预览实现代码
Oct 09 Javascript
JavaScript组件开发之输入框加候选框
Mar 10 Javascript
Bootstrap表单制作代码
Mar 17 Javascript
Vue2.0结合webuploader实现文件分片上传功能
Mar 09 Javascript
对angular4子路由&辅助路由详解
Oct 09 Javascript
Vue多环境代理配置方法思路详解
Jun 21 Javascript
解决Nuxt使用axios跨域问题
Jul 06 Javascript
react的hooks的用法详解
Oct 12 Javascript
AngularJS模板加载用法详解
Nov 04 #Javascript
jQuery 遍历map()方法详解
Nov 04 #Javascript
Sortable.js拖拽排序使用方法解析
Nov 04 #Javascript
jQuery图片加载显示loading效果
Nov 04 #Javascript
JavaScript 深层克隆对象详解及实例
Nov 03 #Javascript
jQuery.ajax实现根据不同的Content-Type做出不同的响应
Nov 03 #Javascript
简单学习vue指令directive
Nov 03 #Javascript
You might like
信用卡效验程序
2006/10/09 PHP
PHP数组实例总结与说明
2011/08/23 PHP
php编写的抽奖程序中奖概率算法
2015/05/14 PHP
模拟多级复选框效果的jquery代码
2013/08/13 Javascript
javascript图片相似度算法实现 js实现直方图和向量算法
2014/01/14 Javascript
JavaScript Serializer序列化时间处理示例
2014/07/31 Javascript
JQuery实现当鼠标停留在某区域3秒后自动执行
2014/09/09 Javascript
js阻止事件追加的具体实现
2014/10/15 Javascript
浅谈Unicode与JavaScript的发展史
2015/01/19 Javascript
JavaScript中Cookies的相关使用教程
2015/06/04 Javascript
javascript瀑布流布局实现方法详解
2016/02/17 Javascript
JS调用Android、Ios原生控件
2017/01/06 Javascript
微信小程序教程系列之设置标题栏和导航栏(7)
2020/06/29 Javascript
js中的闭包学习心得
2018/02/06 Javascript
JavaScript实现简单的文本逐字打印效果示例
2018/04/12 Javascript
vue单页缓存方案分析及实现
2018/09/25 Javascript
使用vue-router切换页面时,获取上一页url以及当前页面url的方法
2019/05/06 Javascript
JavaScript使用面向对象实现的拖拽功能详解
2019/06/12 Javascript
浅谈Three.js截图并下载的大坑
2019/11/01 Javascript
通过js随机函数Math.random实现乱序
2020/05/19 Javascript
[01:04:48]VGJ.S vs TNC Supermajor 败者组 BO3 第一场 6.6
2018/06/07 DOTA
python和pyqt实现360的CLable控件
2014/02/21 Python
使用Python实现下载网易云音乐的高清MV
2015/03/16 Python
Python使用pickle模块存储数据报错解决示例代码
2018/01/26 Python
python中int与str互转方法
2018/07/02 Python
Python判断一个三位数是否为水仙花数的示例
2018/11/13 Python
python函数声明和调用定义及原理详解
2019/12/02 Python
python计算二维矩形IOU实例
2020/01/18 Python
python利用datetime模块计算程序运行时间问题
2020/02/20 Python
Python读写压缩文件的方法
2020/07/30 Python
领导的自我鉴定
2013/12/28 职场文书
2014年应届大学生毕业自我鉴定
2014/01/31 职场文书
环保专项行动方案
2014/05/12 职场文书
八年级英语教学计划
2015/01/23 职场文书
房产电话营销开场白
2015/05/29 职场文书
分析SQL窗口函数之取值窗口函数
2022/04/21 Oracle