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代码
Sep 07 Javascript
jQuery源码分析-05异步队列 Deferred 使用介绍
Nov 14 Javascript
JS判断字符串包含的方法
May 05 Javascript
JavaScript使用DeviceOne开发实战(二) 生成调试安装包
Dec 01 Javascript
js简单判断移动端系统的方法
Feb 25 Javascript
学习使用jquery iScroll.js移动端滚动条插件
Mar 24 Javascript
angular+ionic返回上一页并刷新页面
Aug 08 Javascript
基于node打包可执行文件工具_Pkg使用心得分享
Jan 24 Javascript
JS 中可以提升幸福度的小技巧(可以识别更多另类写法)
Jul 28 Javascript
js遍历详解(forEach, map, for, for...in, for...of)
Aug 28 Javascript
js 计数排序的实现示例(升级版)
Jan 12 Javascript
JavaScript进阶(一)变量声明提升实例分析
May 09 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网站的几个实用要点
2014/12/30 PHP
php实现连接access数据库并转txt写入的方法
2017/02/08 PHP
JavaScript中判断函数是new还是()调用的区别说明
2011/04/07 Javascript
非主流的textarea自增长实现js代码
2011/12/20 Javascript
JavaScript中操作字符串小结
2015/05/04 Javascript
js实现简洁的滑动门菜单(选项卡)效果代码
2015/09/04 Javascript
JQuery+EasyUI轻松实现步骤条效果
2016/02/22 Javascript
JS实现的打字机效果完整实例
2016/06/20 Javascript
NPM 安装cordova时警告:npm WARN deprecated minimatch@2.0.10: Please update to minimatch 3.0.2 or higher to
2016/12/20 Javascript
jQuery插件Echarts实现的渐变色柱状图
2017/03/23 jQuery
JS实现的添加弹出层并完成锁屏操作示例
2017/04/07 Javascript
Node Puppeteer图像识别实现百度指数爬虫的示例
2018/02/22 Javascript
详解axios中封装使用、拦截特定请求、判断所有请求加载完毕)
2019/04/09 Javascript
vue从零实现一个消息通知组件的方法详解
2020/03/16 Javascript
Python装饰器decorator用法实例
2014/11/10 Python
用python实现面向对像的ASP程序实例
2014/11/10 Python
ubuntu 18.04搭建python环境(pycharm+anaconda)
2019/06/14 Python
Python使用Pandas库常见操作详解
2020/01/16 Python
tensorflow多维张量计算实例
2020/02/11 Python
python 实现PIL模块在图片画线写字
2020/05/16 Python
Html5监听手机摇一摇事件的实现
2019/11/07 HTML / CSS
Linux文件操作命令都有哪些
2015/02/27 面试题
Java如何读取CLOB字段
2013/10/10 面试题
村委会贫困证明
2014/01/14 职场文书
《童年的发现》教学反思
2014/02/14 职场文书
马云北大演讲完整版:真心话,什么才是阿里的核心竞争力?
2014/04/04 职场文书
小学优秀班主任事迹材料
2014/05/17 职场文书
工作失误检讨书范文
2015/01/26 职场文书
介绍信格式
2015/01/30 职场文书
关爱留守儿童捐款倡议书
2015/04/27 职场文书
2015年社区工会工作总结
2015/05/26 职场文书
婚育证明格式
2015/06/17 职场文书
教导处教学工作总结
2015/08/12 职场文书
2016年安全月活动总结
2016/04/06 职场文书
如何用python反转图片,视频
2021/04/24 Python
给numpy.array增加维度的超简单方法
2021/06/02 Python