JavaScript 数组的 uniq 方法


Posted in Javascript onJanuary 23, 2008

给Array本地对象增加一个原型方法,它的用途是删除数组条目中重复的条目(可能有多个),返回值是一个包含被删除的重复条目的新数组。

形式化描述:
input
Array(size=N)
output
Array1=Array的无重复保序的子集,
无重复是指,对任意a,b属于Array1,a!=b
保序是指,若a在Array的下标小于b在Array的下标,则a在Array1中的下标也小于b在Array的下标
Array2=Array-Array1,保序
realazy给出了一个新解,思路非常清晰:顺序遍历访问每个元素,如果这个元素的值已经访问过了,则加入Array2,否则加入Array1。判断当前元素的值是否已经访问过所采用的方法是顺序遍历已经访问过的所有元素。 
易见该算法复杂度约O(N^2)。

我在他的算法框架下稍微做了一些改进,关键在于遍历过程中如何判断当前元素的值是否已经访问过。在原数组值域为正整数且极差(range=max value-min value)不太大的条件下,可以采用简单的"桶"算法。
准备一个长度为range的boolean数组b,初始化全为false。对于原数组中每个值value,如果b[value]=true,则表明这个值访问过,放入Array2,否则放入Array1同时令b[value]=true。 
这显然是O(N)的算法,代价是额外的空间复杂度range,而且要求原数组值域为正整数。
不难推广到值域为整数的情形,事实上只需考察桶号value-min(Array)即可转化为正整数的情形。

为了避免range太大造成的空间的浪费,在"桶"算法基础上改进为散列算法,具体说来是线性同余开散列法。目的是将值域压缩映射到一个可控的小的连续正整数子集中,同时保证不同的原象对应的相同的象的概率要尽可能小,也就是说桶与桶之间要尽量负载均衡。 
例如这是一个值域为实数的散列函数:
key=hashFun(value)=Math.floor(value)*37%91
这仍然是O(N)的算法,(显然O(N)是所有uniq算法的复杂度下界),好处是可以控制空间的开销,而且可以适应非整数值域,只需要设计相应的散列函数即可。

下面是桶(bucket)算法的实现:
   var resultArr = [],
       returnArr = [], 
       origLen = this.length,
       resultLen;
   var maxv=this[0],minv=this[0];
   for (var i=1; i<origLen; ++i){
       if(this[i]>maxv)maxv=this[i];
       else if(this[i]<minv)minv=this[i]; 
   }
   var blen=maxv-minv+1;
   var b=new Array(blen);
   for(var i=0;i<blen;++i)b[i]=false;
   for (var i=0; i<origLen; ++i){
       if (b[this[i]-minv]){
           returnArr.push(this[i]); 
       } else {
           resultArr.push(this[i]);
           b[this[i]-minv]=true;
       }
   }
   resultLen = resultArr.length;
   this.length = resultLen;
   for (var i=0; i<resultLen; ++i){ 
       this[i] = resultArr[i];
   }
   return returnArr;
下面是散列(hash)算法的实现
var shuffler = 37
var beta=0.007;
var origLen=this.length
var bucketSize=Math.ceil(origLen*beta);
var hashSet=new Array(bucketSize); 
var hashFun = function(value){
var key = (Math.floor(value)*shuffler)%bucketSize;
return key;
}
//init hashSet
for(var i=0;i<bucketSize;i++)hashSet[i]=new Array();
//
var ret=[],self=[];
var key,value; 
var bucket,openLen;
var everConflict;
for(var i=0;i<origLen;i++){
value=this[i];
key=hashFun(value);
bucket = hashSet[key];
openLen=bucket.length;//if(openLen>1)return;
everConflict=false; 
for(var j=0;j<openLen;j++){
 if(bucket[j]==value){
  ret.push(value);
  everConflict=true;
  break;
 }
}
if(!everConflict){
 bucket.push(value);
 self.push(value);
}
}
   selfLen = self.length;
   this.length = selfLen;
   for (i=0; i<selfLen; ++i){
       this[i] = self[i];
   }
//compute average bucket size
var lens=[],sum=0;
for(var i=0;i<hashSet.length ;++i){lens.push(hashSet[i].length);sum+=hashSet[i].length};
average=sum/hashSet.length;//watch lens,average
   return ret;

用k*10000个0~k*100的随机整数测试计算时间(ms)
k 1 2 3 4 5
realazy 240 693 1399 2301 3807 
bucket 55 101 141 219 293
hash 214 411 654 844 1083
测试框架借鉴了http://realazy.org/lab/uniq.html
测试环境Firefox2.0.0.6/Ubuntu7.10/2.66GHzP4/1024MBDDR 

Javascript 相关文章推荐
js验证表单大全
Nov 25 Javascript
JS 面向对象的5钟写法
Jul 31 Javascript
Dom 是什么的详细说明
Oct 25 Javascript
js 创建快捷方式的代码(fso)
Nov 19 Javascript
用jquery设置按钮的disabled属性的实现代码
Nov 28 Javascript
javascript 兼容所有浏览器的DOM扩展功能
Aug 01 Javascript
javascript 获取HTML DOM父、子、临近节点
Jun 16 Javascript
JavaScript常用的返回,自动跳转,刷新,关闭语句汇总
Jan 13 Javascript
JavaScript插件化开发教程 (二)
Jan 27 Javascript
jQuery实现简单弹窗遮罩效果
Feb 27 Javascript
Vue 中使用 CSS Modules优雅方法
Apr 09 Javascript
Vue 动态组件与 v-once 指令的实现
Feb 12 Javascript
Javascript 更新 JavaScript 数组的 uniq 方法
Jan 23 #Javascript
Javascript 各浏览器的 Javascript 效率对比
Jan 23 #Javascript
Javascript 写的简单进度条控件
Jan 22 #Javascript
用jQuery实现检测浏览器及版本的脚本代码
Jan 22 #Javascript
零基础学JavaScript最新动画教程+iso光盘下载
Jan 22 #Javascript
用js 让图片在 div或dl里 居中,底部对齐
Jan 21 #Javascript
jquery 插件 人性化的消息显示
Jan 21 #Javascript
You might like
destoon实现底部添加你是第几位访问者的方法
2014/07/15 PHP
PHP生成各种常见验证码和Ajax验证过程
2016/01/10 PHP
一款JavaScript压缩工具:X2JSCompactor
2007/06/13 Javascript
javascript笔记 String类replace函数的一些事
2011/09/22 Javascript
JS仿百度搜索自动提示框匹配查询功能
2013/11/21 Javascript
删除条目时弹出的确认对话框
2014/06/05 Javascript
jQuery控制的不同方向的滑动(向左、向右滑动等)
2014/07/18 Javascript
通过点击jqgrid表格弹出需要的表格数据
2015/12/02 Javascript
JS模态窗口返回值兼容问题的完美解决方法
2016/05/28 Javascript
Vue2.0用 watch 观察 prop 变化(不触发)
2017/09/08 Javascript
微信小程序登录session的使用
2019/03/17 Javascript
JS页面获取 session 值,作用域和闭包学习笔记
2019/10/16 Javascript
python中的五种异常处理机制介绍
2014/09/02 Python
python实现ipsec开权限实例
2014/11/11 Python
python用pickle模块实现“增删改查”的简易功能
2017/06/07 Python
pandas DataFrame 删除重复的行的实现方法
2019/01/29 Python
Python datetime包函数简单介绍
2019/08/28 Python
python3 dict ndarray 存成json,并保留原数据精度的实例
2019/12/06 Python
Django中使用MySQL5.5的教程
2019/12/18 Python
Anaconda配置pytorch-gpu虚拟环境的图文教程
2020/04/16 Python
Pycharm新手使用教程(图文详解)
2020/09/17 Python
Topman美国官网:英国著名的国际平价时尚男装品牌
2017/12/22 全球购物
瑞士网球商店:Tennis-Point
2020/03/12 全球购物
波兰最大的电商平台:Allegro.pl
2021/02/06 全球购物
医学生个人求职信范文
2013/09/24 职场文书
出纳岗位职责模板
2013/11/27 职场文书
优秀求职自荐信怎样写
2013/12/18 职场文书
艺人经纪人岗位职责
2014/04/15 职场文书
旅游与酒店管理专业求职信
2014/07/21 职场文书
护理目标管理责任书
2014/07/25 职场文书
销售2014年度工作总结
2014/12/08 职场文书
怒海潜将观后感
2015/06/11 职场文书
2015迎新晚会活动总结
2015/07/16 职场文书
小学体育队列队形教学反思
2016/02/16 职场文书
win10+anaconda安装yolov5的方法及问题解决方案
2021/04/29 Python
python 利用PyAutoGUI快速构建自动化操作脚本
2021/05/31 Python