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 相关文章推荐
自适应图片大小的弹出窗口
Jul 27 Javascript
超酷的网页音乐播放器DewPlayer使用方法
Dec 18 Javascript
JS完整获取IE浏览器信息包括类型、版本、语言等等
May 22 Javascript
IE浏览器不支持getElementsByClassName的解决方法
Aug 27 Javascript
JavaScript中提前声明变量或函数例子
Nov 12 Javascript
jQuery多媒体插件jQuery Media Plugin使用详解
Dec 19 Javascript
angularjs学习笔记之简单介绍
Sep 26 Javascript
理解javascript中的严格模式
Feb 01 Javascript
js实现点击图片自动提交action的简单方法
Oct 16 Javascript
javascript中mouseenter与mouseover的异同
Jun 06 Javascript
详解如何构建一个Angular6的第三方npm包
Sep 07 Javascript
详解vue-cli项目开发/生产环境代理实现跨域请求
Jul 23 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
咖啡冲泡指南 咖啡有哪些制作方式 单品咖啡 意式咖啡
2021/03/06 冲泡冲煮
PHP 和 XML: 使用expat函数(二)
2006/10/09 PHP
再次研究下cache_lite
2007/02/14 PHP
9个PHP开发常用功能函数小结
2011/07/15 PHP
PHP使用数组实现队列
2012/02/05 PHP
深入解析PHP中逗号与点号的区别
2013/08/05 PHP
php校验表单检测字段是否为空的方法
2015/03/20 PHP
Ubuntu VPS中wordpress网站打开时提示”建立数据库连接错误”的解决办法
2016/11/03 PHP
新浪的图片新闻效果
2007/01/13 Javascript
Javascript 中介者模式实例
2009/12/16 Javascript
Confirmer JQuery确认对话框组件
2010/06/09 Javascript
情人节之礼 js项链效果
2012/02/13 Javascript
javascript实现简单的分页特效
2015/08/12 Javascript
原生js制作日历控件实例分享
2016/04/06 Javascript
jquery实用技巧之输入框提示语句
2016/07/28 Javascript
JavaScript实现快速排序的方法分析
2018/01/10 Javascript
简述JS控制台的使用
2018/07/15 Javascript
vue完成项目后,打包成静态文件的方法
2018/09/03 Javascript
js实现坦克大战游戏
2020/02/24 Javascript
JavaScript Html实现移动端红包雨功能页面
2021/01/10 Javascript
[46:55]LGD vs Liquid 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/19 DOTA
python类型强制转换long to int的代码
2013/02/10 Python
Python实现的简单文件传输服务器和客户端
2015/04/08 Python
简介Django框架中可使用的各类缓存
2015/07/23 Python
使用pandas的DataFrame的plot方法绘制图像的实例
2018/05/24 Python
python中dict字典的查询键值对 遍历 排序 创建 访问 更新 删除基础操作方法
2018/09/13 Python
django使用LDAP验证的方法示例
2018/12/10 Python
PyTorch搭建多项式回归模型(三)
2019/05/22 Python
Pytoch之torchvision.transforms图像变换实例
2019/12/30 Python
用OpenCV进行年龄和性别检测的实现示例
2021/01/29 Python
Python使用cn2an实现中文数字与阿拉伯数字的相互转换
2021/03/02 Python
CSS3中使用RGBa来调节透明度的教程
2016/05/09 HTML / CSS
美国沙龙美发产品购物网站:Hair.com by L’Oreal
2020/11/09 全球购物
成人继续教育实施方案
2014/03/01 职场文书
2014年银行信贷员工作总结
2014/12/08 职场文书
文明和谐家庭事迹材料(2016精选版)
2016/02/29 职场文书