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去掉数组中的重复元素
Jan 13 Javascript
动态加载dtree.js树treeview(示例代码)
Dec 17 Javascript
javascript实现3D切换焦点图
Oct 16 Javascript
AngularJS基础 ng-cut 指令介绍及简单示例
Aug 01 Javascript
js无提示关闭浏览器窗口的两种方法分析
Nov 06 Javascript
javascript基础知识之html5轮播图实例讲解(44)
Feb 17 Javascript
基于JavaScript实现微信抢红包功能
Jul 20 Javascript
详解.vue文件解析的实现
Jun 11 Javascript
JavaScript变量作用域及内存问题实例分析
Jun 10 Javascript
vue实现购物车选择功能
Jan 10 Javascript
vue打开其他项目页面并传入数据详解
Nov 25 Vue.js
vue watch监控对象的简单方法示例
Jan 07 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单件模式结合命令链模式使用说明
2008/09/07 PHP
thinkphp中session和cookie无效的解决方法
2014/12/19 PHP
PHP操作MySQL的mysql_fetch_* 函数的常见用法教程
2015/12/25 PHP
PHP中cookie知识点学习
2018/05/06 PHP
用jQuery打造TabPanel效果代码
2010/05/22 Javascript
JavaScript对象链式操作代码(jquery)
2010/07/04 Javascript
在多个页面使用同一个HTML片段的代码
2011/03/04 Javascript
javascript控制Div层透明属性由浅变深由深变浅逐渐显示
2013/11/12 Javascript
jQuery.extend()、jQuery.fn.extend()扩展方法示例详解
2014/05/08 Javascript
详细分析使用AngularJS编程中提交表单的方式
2015/06/19 Javascript
Knockoutjs 学习系列(一)ko初体验
2016/06/07 Javascript
Angular实现的简单查询天气预报功能示例
2017/12/27 Javascript
详解如何在react中搭建d3力导向图
2018/01/12 Javascript
Vuex 模块化使用详解
2019/07/31 Javascript
原生JavaScript实现五子棋游戏
2020/11/09 Javascript
Vue3配置axios跨域实现过程解析
2020/11/25 Vue.js
对Python中数组的几种使用方法总结
2018/06/28 Python
Python 利用内置set函数对字符串和列表进行去重的方法
2018/06/29 Python
opencv python 图像轮廓/检测轮廓/绘制轮廓的方法
2019/07/03 Python
python处理RSTP视频流过程解析
2020/01/11 Python
Python基于gevent实现高并发代码实例
2020/05/15 Python
Python填充任意颜色,不同算法时间差异分析说明
2020/05/16 Python
让IE支持CSS3的不完全兼容方案
2014/09/19 HTML / CSS
前端使用canvas生成盲水印的加密解密的实现
2020/12/16 HTML / CSS
详解如何解决H5开发使用wx.hideMenuItems无效果不生效
2021/01/20 HTML / CSS
会计专业大学生职业生涯规划范文
2014/01/11 职场文书
同学聚会欢迎辞
2014/01/14 职场文书
入学生会自荐书范文
2014/02/05 职场文书
房屋登记授权委托书范本
2014/10/09 职场文书
教育合作协议范本
2014/10/17 职场文书
工会工作个人总结
2015/03/03 职场文书
毕业答辩开场白范文
2015/05/27 职场文书
甲午大海战观后感
2015/06/02 职场文书
党风廉政建设心得体会
2019/05/21 职场文书
请学会珍惜眼前,因为人生没有下辈子!
2019/11/12 职场文书
matplotlib画混淆矩阵与正确率曲线的实例代码
2021/06/01 Python