前端在日常开发中或多或少都会碰到有对数据去重的需求,实际上,像是lodash这些工具库已经有成熟完备的实现,并且可以成熟地运用于生产环境。但是这并不妨碍我们从思维拓展的角度出发,看看去重可以用几种思路去实现。

首先是常规的双层循环比对的思路实现

function doubleLoopUniq(arr) {
let result = [];
for (let i = 0, len = arr.length, isExist; i < len; i++) {
// 定义一个变量表示当前元素在 result 中是否存在。
isExist = false;
for (let j = 0, rLen = result.length; j < rLen; j++) {
if (result[j] === arr[i]) {
// 依次对result 中的元素 和 原数组元素进行比对。
isExist = true;
break;
}
}
// 最后判断如果不存在,则将此元素插入result
!isExist && result.push(arr[i]);
}
return result;
}

借助 js内置的indexOf 进行去重

function indexOfUniq(arr) {
let result = [];
for (let i = 0, len = arr.length; i < len; i++) {
// 用indexOf 简化了二层循环的流程
if (result.indexOf(arr[i]) === -1) result.push(arr[i]);
}
return result;
}

排序后前后比对去重

function sortUniq(arr) {
let result = [], last;
// 这里解构是为了不对原数组产生副作用
[ ...arr ].sort().forEach(item => {
if (item != last) {
result.push(item);
last = item;
}
});
return result;
}

通过hashTable去重

function hashUniq(arr) {
let hashTable = arr.reduce((result, curr, index, array) => {
result[curr] = true;
return result;
}, {})
return Object.keys(hashTable).map(item => parseInt(item, 10));
}

ES6 SET一行代码实现去重

function toSetUniq(arr) {
return Array.from(new Set(arr));
}

splice 去重(直接操作数组本身,带副作用)

function inPlaceUniq(arr) {
let idx = 0;
while (idx < arr.length) {
let compare = idx + 1;
while (compare < arr.length) {
if (arr[idx] == arr[compare]) {
arr.splice(compare, 1);
continue;
}
++compare
}
++idx;
}
return arr;
}

最后在nodejs下面简单跑个测试,看看哪个效率高~

let data = [];
for (var i = 0; i < 100000; i++) {
data.push(Math.random())
} // 实现一个性能测试的装饰器
function performanceTest(fn, descript) {
var a = new Date().getTime();
return function () {
fn.apply(this, [].slice.call(arguments, 0));
console.log(descript, new Date().getTime() - a)
}
} performanceTest(hashUniq, "hashTable")(data)
performanceTest(sortUniq, "sortUniq")(data)
performanceTest(toSetUniq, "toSetUniq")(data)
performanceTest(indexOfUniq, "indexOfUniq")(data)
performanceTest(doubleLoopUniq, "doubleLoopUniq")(data)
performanceTest(inPlaceUniq, "inPlaceUniq")(data)

结果如下

hashTable 168ms
sortUniq 332ms
toSetUniq 80ms
indexOfUniq 4280ms
doubleLoopUniq 13303ms
inPlaceUniq 9977ms

延伸思考: 如果数组内的元素是对象该怎么去重呢?

既然是引用类型,那么不免会使用到deepEqual,固然这种思路可以解答这道问题,但难免不够高效。

从上面的测试中也可见通过new Set 和 hashTable 去重是最高效的。 所以毫无疑问,我们要基于这两种方式去改造,我想用的是hashTable, 另一方面,为了降低深度比较带来的耗时,我尝试用JSON.stringify 将引用类型转化为基本类型。

function collectionUniq(collection) {
let hashTable = {};
collection.forEach(item => {
hashTable[JSON.stringify(item)] = true;
})
return Object.keys(hashTable).map(item => JSON.parse(item))
}

那么问题来了,我们都知道对象的属性是无序的,假如数据是这种情况,那就GG了。

let collection = [ { a: 1, b: 2, c: 3 }, { b: 2, c: 3, a: 1 } ]

有一种toHash的思路,在对这个数组进行一次基本的去重之后,为了保证准确, 先遍历JSON 字符串 => 通过 charCodeAt()拿到每个字符串 的 unicode 编码 => 相加得到一个总数,最后再两两进行比较,数值相等的就是重复的,这样就达到去重的效果了。

function toHash(obj) {
let power = 1;
let res = 0;
const string = JSON.stringify(obj, null, 2);
for (let i = 0, l = string.length; i < l; i++) {
switch (string[i]) {
case '{':
power *= 2
break
case '}':
power /= 2
break
case ' ':
case '\n':
case '\r':
case '\t':
break
default:
res += string[i].charCodeAt(0) * power
}
}
return res
}

这只是一个实现基本的思路,有很大的改进空间,为了减少hash碰撞的可能,可以对一些特殊字符进行权重的增减。

重点是保证碰撞的几率小到比中大奖还小就可以了。

原文地址 :https://segmentfault.com/a/1190000013192950

javascript 数组去重的6种思路的更多相关文章

  1. JavaScript数组去重的7种方式

    1.利用额外数组 function unique(array) {    if (!Array.isArray(array)) return;     let newArray = [];    fo ...

  2. JavaScript数组去重的几种方法

    这个老问题,网上普遍都有了,为什么要再写一遍呢,主要是为了记个笔记... 遍历时搜索结果数组 思路很明确,如下 新建一个数组存放结果 循环遍历原数组,对于每一个元素,在结果数组中搜索是否存在 若不存在 ...

  3. [转] JavaScript数组去重(12种方法)

    数组去重,一般都是在面试的时候才会碰到,一般是要求手写数组去重方法的代码.如果是被提问到,数组去重的方法有哪些?你能答出其中的10种,面试官很有可能对你刮目相看.在真实的项目中碰到的数组去重,一般都是 ...

  4. JavaScript数组去重的10种方法

    「数组去重」的确是个老生常谈的问题了,但是你真正的掌握了吗?平时开发中是不是用最简单粗暴的方法来去重?注意到它的性能问题了吗?当面试官对你回答的四个去重方法都不满意时你可以想出更简单且性能能更好的方法 ...

  5. JavaScript数组去重的四种方法

    今天,洗澡的想一个有趣的问题,使用js给数组去重,我想了四种方法,虽然今天的任务没有完成,5555: 不多说,po代码: //方法一:简单循环去重    Array.prototype.unique1 ...

  6. javascript数组去重的3种方法

    前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! javascript数组去重 <!DOCTYPE html> <html> < ...

  7. JavaScript数组去重(12种方法,史上最全)

    参考博客:https://segmentfault.com/a/1190000016418021?utm_source=tag-newest

  8. JavaScript中数组去重的几种方法

    JavaScript中数组去重的几种方法 正常情况下,数据去重的工作一般都是由后端同事来完成的,但是前端也要掌握好处理数据的能力,万一去重的工作交给我们大前端处理,我们也不能怂呀.现在我总结了一些去重 ...

  9. javascript数组去重算法-----4(另一种写法__2)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. (最短路 spfa)Wormholes -- poj -- 3259

    http://poj.org/problem?id=3259 Wormholes Time Limit: 2000MS   Memory Limit: 65536K Total Submissions ...

  2. android图形系统概述

    简介 本文讲解的内容是Android4.1以后的系统机制,将从整体上分析Android图形显示系统的结构,不深入分析每一层内部的代码实现,更多的是使用流程图和结构图来让大家理解Android是如何绘制 ...

  3. java web 通过前台输入的数据(name-value)保存到后台 xml文件中

    一:项目需求,前端有一个页面,页面中可以手动输入一些参数数据,通过点击前端的按钮,使输入的数据保存到后台生成的.xml文件中 二:我在前端使用的是easyui的propertygrid,这个能通过da ...

  4. 【TypeScript】TypeScript 学习 2——接口

    在 TypeScript 中,接口是用作约束作用的,在编译成 JavaScript 的时候,所有的接口都会被擦除掉,因为 JavaScript 中并没有接口这一概念. 先看看一个简单的例子: func ...

  5. Jersey服务端

    问世间情为何物,直叫人一声呵呵. 上个项目写的jersey restful服务端,怎么都是正确的,没什么问题.结果这个项目写了,呵呵了,真的呵呵了,怎么搞都有问题. 总是报错,对json的类型报错,无 ...

  6. Spring Boot 2 实践记录之 条件装配

    实验项目是想要使用多种数据库访问方式,比如 JPA 和 MyBatis. 项目的 Service 层业务逻辑相同,只是具体实现代码不同,自然是一组接口,两组实现类的架构比较合理. 不过这种模式却有一个 ...

  7. 4.C#WebAPI多版本管理介绍及实现方案详解

    1.什么是 API 的多版本? 说白了就是多版本共存的问题.为方便大家理解我就举个例子吧,大家想必都用过Jquery吧,它的1.*版本做到了对低版本IE的支持:2.*版本还保留着ajax,但是不再支持 ...

  8. 基于VMware Workstation搭建开发服务器

    基于VMware Workstation搭建开发服务器   文章为本人原创,转载请联系作者并注明出处.晓松 源URL: https://www.jianshu.com/p/e62ab7de0124 我 ...

  9. The service definition selected is invalid

    吐槽下 最近在学Java 听闻Java生态很好 社区很多 但实际操作起来确实另一番风景 不多说了 说正事 添加WebService服务Client时有密码认证得服务 Eclipse抛出 The ser ...

  10. Svn和jekins的使用

    首先是svn的安装, 在安装svn的服务端时,需要注意选择第二项,这样才能在idea中使用svn, 然后就是在idaa中配置svn插件. 插件的使用 从svn库中检出项目 然后在这个地址中填入你需要导 ...