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 页面刷新location.reload和location.replace的区别小结
Dec 24 Javascript
浅析showModalDialog数据缓存问题(用禁止浏览器缓存解决)
Jul 09 Javascript
制作jquery遮罩层效果导航菜单代码分享
Dec 25 Javascript
使用jQuery中的when实现多个AJAX请求对应单个回调的例子分享
Apr 23 Javascript
EasyUI,点击开启编辑框,并且编辑框获得焦点的方法
Mar 01 Javascript
详解 javascript中offsetleft属性的用法
Nov 11 Javascript
javascript函数中的3个高级技巧
Sep 22 Javascript
微信小程序之电影影评小程序制作代码
Aug 03 Javascript
vue项目中使用tinymce编辑器的步骤详解
Sep 11 Javascript
node中的session的具体使用
Sep 14 Javascript
Jquery异步上传文件代码实例
Nov 13 jQuery
微信小程序实现上拉加载功能
Nov 20 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
Zerg建筑一览
2020/03/14 星际争霸
php模板函数 正则实现代码
2012/10/15 PHP
利用PHP生成静态html页面的原理
2016/09/30 PHP
yii框架结合charjs实现统计30天数据的方法
2020/04/04 PHP
动手学习无线电
2021/03/10 无线电
判断多个input type=file是否有已经选择好文件的代码
2012/05/23 Javascript
使用js实现关闭js弹出层的窗口
2014/02/10 Javascript
用console.table()调试javascript
2014/09/04 Javascript
jQuery实现鼠标经过图片变亮其他变暗效果
2015/05/08 Javascript
Angularjs中UI Router的使用方法
2016/05/14 Javascript
简单理解vue中track-by属性
2016/10/26 Javascript
webpack踩坑之路图片的路径与打包
2017/09/05 Javascript
微信小程序中换行空格(多个空格)写法详解
2018/07/10 Javascript
Vue 指令实现按钮级别权限管理功能
2019/04/23 Javascript
使用Vue 实现滑动验证码功能
2019/06/27 Javascript
JQuery复选框全选效果如何实现
2020/05/08 jQuery
[01:03:33]Alliance vs TNC 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/18 DOTA
详细解读Python中的__init__()方法
2015/05/02 Python
详解Python编程中对Monkey Patch猴子补丁开发方式的运用
2016/05/27 Python
Django中Model的使用方法教程
2018/03/07 Python
python 创建一个空dataframe 然后添加行数据的实例
2018/06/07 Python
Python中的groupby分组功能的实例代码
2018/07/11 Python
Python2和Python3中urllib库中urlencode的使用注意事项
2018/11/26 Python
python random从集合中随机选择元素的方法
2019/01/23 Python
Python flask路由间传递变量实例详解
2020/06/03 Python
Html5 Canvas 实现一个“刮刮乐”游戏
2019/09/05 HTML / CSS
Casadei卡萨蒂官网:意大利奢侈鞋履品牌
2017/10/28 全球购物
通信工程毕业生自荐信
2013/11/01 职场文书
交通事故赔偿协议书
2014/04/15 职场文书
访谈节目策划方案
2014/05/15 职场文书
2014年有孩子的离婚协议书范本
2014/10/08 职场文书
教师先进事迹材料
2014/12/16 职场文书
上课迟到检讨书
2015/05/06 职场文书
导游词之日本富士山
2020/01/06 职场文书
PyCharm 安装与使用配置教程(windows,mac通用)
2021/05/12 Python
5种 JavaScript 方式实现数组扁平化
2021/10/05 Javascript