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中将URL中的参数提取出来作为对象的实现代码
Aug 16 Javascript
javascript改变position值实现菜单滚动至顶部后固定
Jan 18 Javascript
js 时间函数应用加、减、比较、格式转换的示例代码
Aug 23 Javascript
jquery实现点击文字可编辑并修改保存至数据库
Apr 15 Javascript
javascript实现跨域的方法汇总
Jun 25 Javascript
jQuery Validation PlugIn的使用方法详解
Dec 18 Javascript
高效利用Angular中内置服务$http、$location等
Mar 22 Javascript
vue 项目打包通过命令修改 vue-router 模式 修改 API 接口前缀
Jun 13 Javascript
webpack实现一个行内样式px转vw的loader示例
Sep 13 Javascript
ES6 fetch函数与后台交互实现
Nov 14 Javascript
详解webpack4.x之搭建前端开发环境
Mar 28 Javascript
40行代码把Vue3的响应式集成进React做状态管理
May 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
如何在WIN2K下安装PHP4.04
2006/10/09 PHP
php生成SessionID和图片校验码的思路和实现代码
2009/03/10 PHP
通过php快速统计某个数据库中每张表的数据量
2012/09/04 PHP
ThinkPHP标签制作教程
2014/07/10 PHP
php中define用法实例
2015/07/30 PHP
Laravel中10个有用的用法小结
2019/05/06 PHP
PHP使用openssl扩展实现加解密方法示例
2020/02/20 PHP
几行代码轻松搞定jquery实现flash8类似的连接效果
2007/05/03 Javascript
jquery构造器的实现代码小结
2011/05/16 Javascript
javascript 获取图片尺寸及放大图片
2013/09/04 Javascript
Jquery easyUI 更新行示例
2014/03/06 Javascript
Bootstrap弹出带合法性检查的登录框实例代码【推荐】
2016/06/23 Javascript
js将table的每个td的内容自动赋值给其title属性的方法
2016/10/13 Javascript
WebSocket实现简单客服聊天系统
2017/05/12 Javascript
vue获取DOM元素并设置属性的两种实现方法
2017/09/30 Javascript
vue监听键盘事件的快捷方法【推荐】
2018/07/11 Javascript
如何为vue的项目添加单元测试
2018/12/19 Javascript
Vue作用域插槽实现方法及作用详解
2020/07/08 Javascript
python创建临时文件夹的方法
2015/07/06 Python
特征脸(Eigenface)理论基础之PCA主成分分析法
2018/03/13 Python
Python把csv数据写入list和字典类型的变量脚本方法
2018/06/15 Python
详解pandas使用drop_duplicates去除DataFrame重复项参数
2019/08/01 Python
在PyTorch中Tensor的查找和筛选例子
2019/08/18 Python
win10下opencv-python特定版本手动安装与pip自动安装教程
2020/03/05 Python
解决tensorflow模型压缩的问题_踩坑无数,总算搞定
2021/03/02 Python
亚洲最大旅游体验平台:KKday
2017/10/21 全球购物
意大利独特而优质的家居用品:Fazzini
2018/12/05 全球购物
几个常见的消息中间件(MOM)
2014/01/08 面试题
学校办公室主任职责
2013/12/27 职场文书
表扬信格式
2014/01/12 职场文书
启动仪式策划方案
2014/06/14 职场文书
硕士毕业答辩开场白
2015/05/27 职场文书
企业愿景口号
2015/12/25 职场文书
2016年小学圣诞节活动总结
2016/03/31 职场文书
你真的了解PHP中的引用符号(&)吗
2021/05/12 PHP
十大好看的穿越动漫排名:《瑞克和莫蒂》第一,国漫《有药》在榜
2022/03/18 日漫