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 相关文章推荐
关于JavaScript的gzip静态压缩方法
Jan 05 Javascript
jQuery使用$.ajax进行即时验证的方法
Dec 08 Javascript
Bootstrap实现响应式导航栏效果
Dec 28 Javascript
基于javascript实现泡泡大冒险网页版小游戏
Mar 23 Javascript
用AngularJS的指令实现tabs切换效果
Aug 31 Javascript
Validform表单验证总结篇
Oct 31 Javascript
jQuery中ajax错误调试分析
Dec 01 Javascript
bootstrap表格分页实例讲解
Dec 30 Javascript
微信小程序  http请求封装详解及实例代码
Feb 15 Javascript
addeventlistener监听scroll跟touch(实例讲解)
Aug 04 Javascript
React Native模块之Permissions权限申请的实例相机
Sep 28 Javascript
Jquery属性的获取/设置及样式添加/删除操作技巧分析
Dec 23 jQuery
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
德生PL990的分析评价
2021/03/02 无线电
PHP读MYSQL中文乱码的解决方法
2006/12/17 PHP
深入php define()函数以及defined()函数的用法详解
2013/06/05 PHP
ThinkPHP上使用多说评论插件的方法
2014/10/31 PHP
Laravel实现autoload方法详解
2017/05/07 PHP
Laravel框架实现定时发布任务的方法
2018/08/16 PHP
JS字符串函数扩展代码
2011/09/13 Javascript
js获得当前时区夏令时发生和终止的时间代码
2014/02/23 Javascript
Jquery Ajax方法传值到action的方法
2014/05/11 Javascript
实现placeholder效果的方案汇总
2015/06/11 Javascript
js点击列表文字对应该行显示背景颜色的实现代码
2015/08/05 Javascript
JavaScript缓冲运动实现方法(2则示例)
2016/01/08 Javascript
jQuery页面加载初始化的3种方法(推荐)
2016/06/02 Javascript
EditPlus 正则表达式 实战(3)
2016/12/15 Javascript
mongoose中利用populate处理嵌套的方法
2017/05/26 Javascript
Javarscript中模块(module)、加载(load)与捆绑(bundle)详解
2017/05/28 Javascript
详解vue渲染函数render的使用
2017/12/12 Javascript
Vue的watch和computed方法的使用及区别介绍
2018/09/06 Javascript
解决cordova+vue 项目打包成APK应用遇到的问题
2019/05/10 Javascript
JavaScript 链表定义与使用方法示例
2020/04/28 Javascript
vant-ui组件调用Dialog弹窗异步关闭操作
2020/11/04 Javascript
分享给Python新手们的几道简单练习题
2017/09/21 Python
python模拟哔哩哔哩滑块登入验证的实现
2020/04/24 Python
关于Theano和Tensorflow多GPU使用问题
2020/06/19 Python
如何基于Python Matplotlib实现网格动画
2020/07/20 Python
详解pandas中利用DataFrame对象的.loc[]、.iloc[]方法抽取数据
2020/12/13 Python
python文件路径操作方法总结
2020/12/21 Python
Matlab使用Plot函数实现数据动态显示方法总结
2021/02/25 Python
HTML5新标签兼容——&gt; 的两种方法
2018/09/12 HTML / CSS
五分钟学会HTML5的WebSocket协议
2019/11/22 HTML / CSS
战友聚会邀请函
2014/01/18 职场文书
社保代办委托书怎么写
2014/10/06 职场文书
2015年世界环境日活动总结
2015/02/11 职场文书
公司食堂管理制度
2015/08/05 职场文书
关于CSS浮动与取消浮动的问题
2021/06/28 HTML / CSS
Netflix《海贼王》真人版剧集多张片场照曝光
2022/04/04 日漫