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 相关文章推荐
jQuery 瀑布流 绝对定位布局(二)(延迟AJAX加载图片)
May 23 Javascript
单击复制文字兼容各浏览器的完美解决方案
Jul 04 Javascript
仿新浪微博登陆邮箱提示效果的js代码
Aug 02 Javascript
javascript将相对路径转绝对路径示例
Mar 14 Javascript
原生javascript实现的分页插件pagenav
Aug 28 Javascript
基于BootStrap Metronic开发框架经验小结【五】Bootstrap File Input文件上传插件的用法详解
May 12 Javascript
jquery根据td给相同tr下其他td赋值的实现方法
Oct 05 Javascript
原生JS实现图片左右轮播
Dec 30 Javascript
BootStrap中Table隐藏后显示问题的实现代码
Aug 31 Javascript
JS使用正则表达式找出最长连续子串长度
Oct 26 Javascript
element-ui 上传图片后清空图片显示的实例
Sep 04 Javascript
基于vue2的canvas时钟倒计时组件步骤解析
Nov 05 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
php中通过curl模拟登陆discuz论坛的实现代码
2012/02/16 PHP
使用php统计字符串中中英文字符的个数
2013/06/23 PHP
ThinkPHP5.0框架实现切换数据库的方法分析
2019/10/30 PHP
JavaScript 学习初步 入门教程
2010/03/25 Javascript
在次封装easyui-Dialog插件实现代码
2010/11/14 Javascript
初窥JQuery-Jquery简介 入门了解篇
2010/11/25 Javascript
jQuery对下拉框,单选框,多选框的操作
2014/02/21 Javascript
JavaScript实现鼠标点击后层展开效果的方法
2015/05/13 Javascript
javascript实现table表格隔行变色的方法
2015/05/13 Javascript
javascript实现在下拉列表中显示多级树形菜单的方法
2015/08/12 Javascript
AngularJS基础 ng-csp 指令详解
2016/08/01 Javascript
AngularJS 实现JavaScript 动画效果详解
2016/09/08 Javascript
jQuery实现的无限级下拉菜单功能示例
2016/09/12 Javascript
JQuery中解决重复动画的方法
2016/10/17 Javascript
微信小程序中做用户登录与登录态维护的实现详解
2017/05/17 Javascript
对angular2中的ngfor和ngif指令嵌套实例讲解
2018/09/12 Javascript
Cookbook组件形式:优化 Vue 组件的运行时性能
2018/11/25 Javascript
electron 如何将任意资源打包的方法步骤
2020/04/16 Javascript
ES6的循环与可迭代对象示例详解
2021/01/31 Javascript
[00:12]DAC2018 no[o]ne亮相SOLO赛 他是否如他的id一样无人可挡?
2018/04/06 DOTA
[01:27:43]VGJ.S vs TNC Supermajor 败者组 BO3 第三场 6.6
2018/06/07 DOTA
基于python生成器封装的协程类
2019/03/20 Python
python的pytest框架之命令行参数详解(下)
2019/06/27 Python
Java Spring项目国际化(i18n)详细方法与实例
2020/03/20 Python
Python接口自动化测试框架运行原理及流程
2020/11/30 Python
Python 实现一个简单的web服务器
2021/01/03 Python
CSS3 简单又实用的5个属性
2010/03/04 HTML / CSS
css3类选择器之结合元素选择器和多类选择器用法
2017/03/09 HTML / CSS
利用纯html5绘制出来的一款非常漂亮的时钟
2015/01/04 HTML / CSS
HTML块级标签汇总(小篇)
2016/07/13 HTML / CSS
ASOS西班牙官网:英国在线时尚和美容零售商
2020/01/10 全球购物
公司联欢晚会主持词
2014/03/22 职场文书
2015年计生工作总结范文
2015/04/24 职场文书
科技活动总结范文
2015/05/11 职场文书
创业计划书之养殖业
2019/10/11 职场文书
Dubbo+zookeeper搭配分布式服务的过程详解
2022/04/03 Java/Android