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 错误处理的几种方法
Jun 13 Javascript
提高网站性能之 如何对待JavaScript
Oct 31 Javascript
js报错 Object doesn't support this property or method的原因分析
Mar 31 Javascript
javascript中String类的subString()方法和slice()方法
May 24 Javascript
zTree插件之多选下拉菜单实例代码
Nov 06 Javascript
基于jquery实现鼠标滚轮驱动的图片切换效果
Oct 26 Javascript
JS焦点图,JS 多个页面放多个焦点图的实例
Dec 08 Javascript
jQuery插件FusionCharts绘制2D双折线图效果示例【附demo源码】
Apr 14 jQuery
微信小程序之swiper滑动面板用法示例
Dec 04 Javascript
vue组件之间通信实例总结(点赞功能)
Dec 05 Javascript
详解vue组件之间的通信
Aug 30 Javascript
Vue看了就会的8个小技巧
Jan 21 Vue.js
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
PHP 开发环境配置(Zend Studio)
2010/04/28 PHP
php设计模式小结
2013/02/15 PHP
详解PHP实现执行定时任务
2015/12/21 PHP
javascript 控制 html元素 显示/隐藏实现代码
2009/09/01 Javascript
jQuery toggle()设置CSS样式
2009/11/05 Javascript
一个简单的js渐显(fadeIn)渐隐(fadeOut)类
2010/06/19 Javascript
使用jquery为table动态添加行的实现代码
2011/03/30 Javascript
jquery获取div宽度的实现思路与代码
2013/01/13 Javascript
jQuery select表单提交省市区城市三级联动核心代码
2014/06/09 Javascript
Egret引擎开发指南之编译项目
2014/09/03 Javascript
javascript学习笔记(五)原型和原型链详解
2014/10/08 Javascript
跟我学习javascript的this关键字
2020/05/28 Javascript
浅谈JavaScript for循环 闭包
2016/06/22 Javascript
javascript自执行函数
2017/02/10 Javascript
Nodejs+Socket.io实现通讯实例代码
2017/02/13 NodeJs
Vue.js实现一个SPA登录页面的过程【推荐】
2017/04/29 Javascript
BootStrap Table实现server分页序号连续显示功能(当前页从上一页的结束序号开始)
2017/09/12 Javascript
JavaScript 判断iPhone X Series机型的方法
2019/01/28 Javascript
iview form清除校验状态的实现
2019/09/19 Javascript
详解微信小程序工程化探索之webpack实战
2020/04/20 Javascript
Python urllib、urllib2、httplib抓取网页代码实例
2015/05/09 Python
python中实现字符串翻转的方法
2018/07/11 Python
python3.6使用pickle序列化class的方法
2018/10/22 Python
解决django model修改添加字段报错的问题
2019/11/18 Python
python requests.get带header
2020/05/05 Python
Python基于httpx模块实现发送请求
2020/07/07 Python
Python3爬虫中关于Ajax分析方法的总结
2020/07/10 Python
Pycharm创建文件时自动生成文件头注释(自定义设置作者日期)
2020/11/24 Python
加拿大床上用品、家居装饰、厨房和浴室产品购物网站:Linen Chest
2018/06/05 全球购物
硕士研究生自我鉴定范文
2013/12/27 职场文书
员工工作能力评语
2014/12/31 职场文书
万能检讨书
2015/01/27 职场文书
导游词之潮音寺
2019/09/26 职场文书
MySQL Threads_running飙升与慢查询的相关问题解决
2021/05/08 MySQL
新手入门Mysql--概念
2021/06/18 MySQL
CSS SandBox应用场景及常见问题
2022/06/25 HTML / CSS