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 CSS样式控制 学习笔记
Jul 23 Javascript
Javascript 面向对象 对象(Object)
May 13 Javascript
使用jQuery管理选择结果
Jan 20 Javascript
分享9点个人认为比较重要的javascript 编程技巧
Apr 27 Javascript
jQuery获取及设置表单input各种类型值的方法小结
May 24 Javascript
AngularJS 路由详解和简单实例
Jul 28 Javascript
无法获取隐藏元素宽度和高度的解决方案
Mar 07 Javascript
微信小程序新增的拖动组件movable-view使用教程
May 20 Javascript
vue计算属性时v-for处理数组时遇到的一个bug问题
Jan 21 Javascript
JavaScript中EventLoop介绍
Jan 22 Javascript
Vue实现自定义下拉菜单功能
Jul 16 Javascript
JQuery实现ul中添加LI和删除指定的Li元素功能完整示例
Oct 16 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
PHP4实际应用经验篇(1)
2006/10/09 PHP
PHP查找数值数组中不重复最大和最小的10个数的方法
2015/04/20 PHP
Jquery插件easyUi表单验证提交(示例代码)
2013/12/30 Javascript
window.location不跳转的问题解决方法
2014/04/17 Javascript
JS实现进入页面时渐变背景色的方法
2015/02/25 Javascript
JavaScript实现数字数组按照倒序排列的方法
2015/04/06 Javascript
jquery实现Slide Out Navigation滑出式菜单效果代码
2015/09/07 Javascript
基于jquery实现鼠标滚轮驱动的图片切换效果
2015/10/26 Javascript
基于jquery实现页面滚动时顶部导航显示隐藏
2020/04/20 Javascript
基于jQuery插件实现点击小图显示大图效果
2016/05/11 Javascript
Angularjs之filter过滤器(推荐)
2016/11/27 Javascript
Bootstrap modal使用及点击外部不消失的解决方法
2016/12/13 Javascript
详解react-router4 异步加载路由两种方法
2017/09/12 Javascript
微信小程序使用navigateTo数据传递的实例
2017/09/26 Javascript
Redux实现组合计数器的示例代码
2018/07/04 Javascript
nodejs 使用nodejs-websocket模块实现点对点实时通讯
2018/11/28 NodeJs
javascript设计模式 ? 适配器模式原理与应用实例分析
2020/04/13 Javascript
element-ui 实现响应式导航栏的示例代码
2020/05/08 Javascript
vue3.0 加载json的方法(非ajax)
2020/10/26 Javascript
Sanic框架路由用法实例分析
2018/07/16 Python
pygame游戏之旅 添加icon和bgm音效的方法
2018/11/21 Python
Python从Excel中读取日期一列的方法
2018/11/28 Python
python2.7使用plotly绘制本地散点图和折线图
2019/04/02 Python
浅谈python图片处理Image和skimage的区别
2019/08/04 Python
python防止随意修改类属性的实现方法
2019/08/21 Python
Python新手学习标准库模块命名
2020/05/29 Python
tensorflow 2.0模式下训练的模型转成 tf1.x 版本的pb模型实例
2020/06/22 Python
CSS 3.0文字悬停跳动特效代码
2020/10/26 HTML / CSS
Html5新增标签与样式及让元素水平垂直居中
2019/07/11 HTML / CSS
国际花店:Pickup Flowers
2020/04/10 全球购物
优秀员工推荐信
2014/05/10 职场文书
代办出身证明书
2014/10/21 职场文书
幼儿园园务工作总结2015
2015/05/18 职场文书
3招让你摆脱即兴讲话冷场尴尬
2019/08/08 职场文书
聊聊golang中多个defer的执行顺序
2021/05/08 Golang
一文弄懂MySQL中redo log与binlog的区别
2022/02/15 MySQL