JavaScript 数据结构之 用 Object 做 索引 实现快速检索

随着Web前端技术的不断发展,技术团队的不断壮大,越来越多的数据需要放在前端用JavaScript做处理。本篇我就来介绍一下,如何使用 Object 对象做索引,从而实现信息的快速检索。

场景一:根据ID找到学生信息

拿学生信息管理举例说明吧,其实公司里的员工管理,药店里的药品管理及分类管理都是类似的。

场景说明

在学生列表页面,后端把20名学生(每页20条数据)的所有信息都给到了Web前端;前端根据情况选择比较重要的信息在列表中显示。如果需要查看学生的详细信息,则需要点击“学生名”,或该点击对应列的“查看详情”按钮。

一般情况下在列表中,可点击部分都会绑定该第信息的“唯一标识码”(ID)。所以前端需要根据这个“唯一标识码”检索出对应学生的信息并显示出来。

在列表页面学生信息的结构如下面的代码段所示:

var students = [
    {id:1,name:"仵士杰",gender:"男",birthday:"1990-02-03",……},
    {id:2,name:"张珍珍",gender:"女",birthday:"1989-02-08",……},
     ……
];

需要强调以下几点:

  1. 在列表页面,学生的所有信息都已经加载到Web前端;
  2. 在列表页面仅显示了比较重要的学生信息,如:姓名、性别,班级;
  3. 详细信息页面包含列表页面所没有的信息,如:入学时间,年龄,证件照、学费金额、学费缴纳状态等;

一般做法

可能有人会想到,每次“查看详细信息”时就向后端发起一次请求。如果在列表页面仅是加载了学生的部分信息,而详情页面中显示的很多信息在列表页面中没有加载的情况下,只能用这种方式。当然我们例举的这个场景下这种做法也可以,但是对于一个在程序优化方面有强迫症且有些偏执的人来说,是绝对不会这么做的。

还有人想到了可以使用循环,代码如下:

function getStudentById(id){
  for(var i=0; i<students.length;i++){
    if(students[i].id == id){
      return students[i];
    }
  }
}

或者有人觉得循环的效率太低,于是想先对 students 数组排序,然后用二分查找。这是一个好的想法,但必须保证所选择的排序算法有较高的效率。否则还不如使用上面的循环。

以上这些方法中,最优的应该是二分查找;但门槛较高,需要写一个高效率的排序,然后还需要写二分查找的算法。

用 Object 做索引

在JavaScript中,Object 对象可以动态增加属性,对属性的访问速度是非常快的(可暂且认为与平衡二叉树的叶子结点的访问速度相同)。所以可以利用Object对象的这一特点构造快速检索的数据结构。

针对此场景生成 可快速检索的 Object 对象的代码如下:

var stuObj = {};
for(var i=0; i<students.length;i++){
  stuObj["_"+students[i].id] = students[i];
}

上面的代码生成了一个 stuObj 对象,这个对象中的属性与 students 数组中元素的id一一对应。可使用如下代码完成快速检索:

function getStudentById(id){
  return stuObj["_"+id];
}

小结

每次“查看详细信息”都向服务端发起一次请求的方案是最差的,这一点应该不会有异议。

使用循环的方式进行查找的时间复杂度是 O(n)。

排序后进行二分查找时,假设使用了效率较高的排序算法(如快排,n*logn)。二分查找的时间复杂度是 logn 。则总体时间复杂度为:n*logn /n+logn = 2logn。但这种方式需要我们写复杂的排序和二分查找算法,有些得不尝失。

最后分析用Object 做索引的方案。每次向Object中增加属性的时间复杂度是 logn(n是Object中当前属性的数量) ,外面有个for循环时间复杂度为n。而检索时的时间复杂度是 logn(n是Object中当前属性的数量)。所以总体时间复杂度约为: n*logn/n +logn = 2logn。

虽然我们用 Object 做索引时,在时间复杂度上与“快速排序+二分查找”相同,但是这种方案容易实现。不用写复杂的快排和二分查找算法。

场景二:多级联动时查找下一级select元素应该需要显示的option。

简单点,举一个“省、市、县”三级联动的例子吧。

场景说明

后端一次性把全国所有的省、市、县信息及它们之间的所属关系都发送到前端了。后面的事全部交给前端处理。原始数据结构如下面的代码段所示:

// 省
var province=[{name:"北京",id:1},{name:"河北",id:2},{name:"河南",id:3},……];

// 市
var city=[{name:"郑州市",id:1,province_id:3},{name:"周口",id:2,province_id:3},……];

// 县
var county=[{name:"郸城县",id:1,city_id:2},{name:"西化县",id:2,city_id:2},……];

当我选中一个省的时候,在第二级的select上元素需要显示该省下面所有的市以供选择。当我选择一个市时,在第三级的select元素上需要显示对应市下面所有的县以供选择。

一般做法

循环方式,当选中一个省时的示例代码如下:

function getCitysByProvinceId(province_id){
  var results = [];
  for(var i=0;i<city.length;i++){
    if(province_id == city[i].province_id){
      results.push(city[i]);
    }
  }
  return results;
}

当选中一个市时,获取市下面所有县的代码与上面的代码类似。

用 Object 做索引

首先需要创建索引,代码如下:

var cityByProvinceId = {};
for(var i=0;i<city.length;i++){
  if(!cityByProvinceId["_"+city[i].province_id]){
    cityByProvinceId["_"+city[i].province_id] = [];
  }
  cityByProvinceId["_"+city[i].province_id].push(city[i]);
}

索引完成后,检索就容易了,并且效率会非常之高:

function getCityByProvinceId(province_id){
  return cityByProvinceId["_"+province_id];
}

选择市时对县的处理方式,与选择省时对市的处理方式完全相同,在此不再赘述。

总结

在Web前端,需要用到快速检索的地方,用 Object 做索引的方式来完成是一个非常好的方案。首先,Object 中属性的检索效率是由JavaScript引擎优化过的,值得信赖。其次,没有复杂的算法和逻辑,代码清晰易读。即提高了效率又简化了代码,何乐而不为呢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,522评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,601评论 18 139
  • 第一章 绪论 什么是数据结构? 数据结构的定义:数据结构是相互之间存在一种或多种特定关系的数据元素的集合。 第二章...
    SeanCheney阅读 5,743评论 0 19
  • 我不想你 真的 不服你看 我最亲密的朋友 也说我没事 我不想你 确实 不然怎么说 雨下得那么大 我依然快乐地吃着鸡...
    懒墨阅读 230评论 0 6
  • 旅行通常是从我习惯的城市走向你习惯的城市里,感受不一样的风土人情、不一样的人间烟火,能量上叫换气,现实生活叫出去走...
    刘红的香气世界阅读 557评论 0 0