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基础篇(6)之函数表达式闭包
Dec 11 Javascript
jQuery实现的鼠标滑过弹出放大图片特效
Jan 08 Javascript
jQuery 获取多选框的值及多选框中文的函数
May 16 Javascript
微信小程序开发之入门实例教程篇
Mar 07 Javascript
js CSS3实现卡牌旋转切换效果
Jul 04 Javascript
使用jQuery实现鼠标点击左右按钮滑动切换
Aug 04 jQuery
Three.js入门之hello world以及如何绘制线
Sep 25 Javascript
深入理解Vue 单向数据流的原理
Nov 09 Javascript
bmob js-sdk 在vue中的使用教程
Jan 21 Javascript
vue多页面开发和打包正确处理方法
Apr 20 Javascript
Vue3.x源码调试的实现方法
Oct 13 Javascript
jQuery--遍历操作实例小结【后代、同胞及过滤】
May 22 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
php遍历类中包含的所有元素的方法
2015/05/12 PHP
PHP 类与构造函数解析
2017/02/06 PHP
PHP 断点续传实例详解
2017/11/11 PHP
图片在浏览器中底部对齐 解决方法之一
2011/11/30 Javascript
jquery多选项卡效果实例代码(附效果图)
2013/03/23 Javascript
javascript使用isNaN()函数判断变量是否为数字
2013/09/21 Javascript
js模仿hover的具体实现代码
2013/12/30 Javascript
PHP使用方法重载实现动态创建属性的get和set方法
2014/11/17 Javascript
javascript常用的方法分享
2015/07/01 Javascript
JS中递归函数
2016/06/17 Javascript
Bootstrap基本组件学习笔记之按钮组(8)
2016/12/07 Javascript
jQuery插件FusionCharts绘制的3D双柱状图效果示例【附demo源码】
2017/04/20 jQuery
javascript实现二叉树遍历的代码
2017/06/08 Javascript
JS设置随机出现2个数字的实例代码
2017/07/19 Javascript
JS加密插件CryptoJS实现的DES加密示例
2018/08/16 Javascript
分享一个vue项目“脚手架”项目的实现步骤
2019/05/26 Javascript
layui递归实现动态左侧菜单
2019/07/26 Javascript
使用typescript快速开发一个cli的实现示例
2020/12/09 Javascript
nodejs+express最简易的连接数据库的方法
2020/12/23 NodeJs
详解Python中的__new__()方法的使用
2015/04/09 Python
基于Python实现的百度贴吧网络爬虫实例
2015/04/17 Python
python中的编码知识整理汇总
2016/01/26 Python
使用python对excle和json互相转换的示例
2018/10/23 Python
python+opencv实现摄像头调用的方法
2019/06/22 Python
flask/django 动态查询表结构相同表名不同数据的Model实现方法
2019/08/29 Python
Python BeautifulReport可视化报告代码实例
2020/04/13 Python
python中shell执行知识点
2020/05/06 Python
Python 使用xlwt模块将多行多列数据循环写入excel文档的操作
2020/11/10 Python
使用Python封装excel操作指南
2021/01/29 Python
应用心理学个人的求职信
2013/12/08 职场文书
面试后感谢信
2014/02/01 职场文书
审计专业自荐信范文
2014/04/21 职场文书
2015年全国爱耳日活动总结
2015/02/27 职场文书
Python数据分析入门之数据读取与存储
2021/05/13 Python
Python下opencv使用hough变换检测直线与圆
2021/06/18 Python
基于HTML十秒做出淘宝页面
2021/10/24 HTML / CSS