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无缝滚动代码
Jan 03 Javascript
jQuery中的val()示例应用
Feb 26 Javascript
javascript操作excel生成报表示例
May 08 Javascript
什么是MEAN?JavaScript编程中的MEAN是什么意思?
Dec 18 Javascript
使用jQuery Mobile框架开发移动端Web App的入门教程
May 17 Javascript
深入解析JavaScript中的立即执行函数
May 21 Javascript
浅谈js停止事件冒泡 阻止浏览器的默认行为(阻止超连接 #)
Feb 08 Javascript
Vue 实现展开折叠效果的示例代码
Aug 27 Javascript
快速解决vue-cli在ie9+中无效的问题
Sep 04 Javascript
redux处理异步action解决方案
Mar 22 Javascript
Vue3+elementui plus创建项目的方法
Dec 01 Vue.js
详解如何解决使用JSON.stringify时遇到的循环引用问题
Mar 23 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中去掉字符串首尾空格的方法
2012/05/19 PHP
Yii PHP Framework实用入门教程(详细介绍)
2013/06/18 PHP
关于PHPDocument 代码注释规范的总结
2013/06/25 PHP
PHP实现绘制3D扇形统计图及图片缩放实例
2014/10/01 PHP
浅谈php提交form表单
2015/07/01 PHP
laravel通过创建自定义artisan make命令来新建类文件详解
2017/08/17 PHP
Laravel 5+ .env环境配置文件详解
2020/04/06 PHP
日历查询的算法 如何计算某一天是星期几
2012/12/12 Javascript
Js数组的操作push,pop,shift,unshift等方法详细介绍
2012/12/28 Javascript
javascript实现原生ajax的几种方法介绍
2013/09/21 Javascript
jQuery中removeData()方法用法实例
2014/12/27 Javascript
js计算任意值之间随机数的方法
2015/01/16 Javascript
javascript实现图片循环渐显播放的方法
2015/02/24 Javascript
js实现带缓冲效果的仿QQ面板折叠菜单代码
2015/09/06 Javascript
AngularJS入门教程之静态模板详解
2016/08/18 Javascript
JavaScript实现审核流程状态的动态显示进度条
2017/03/15 Javascript
大白话讲解JavaScript的Promise
2017/04/06 Javascript
一个基于react的图片裁剪组件示例
2018/04/18 Javascript
详解webpack引入第三方库的方式以及注意事项
2019/01/15 Javascript
JavaScript中构造函数与原型链之间的关系详解
2019/02/25 Javascript
python简单读取大文件的方法
2016/07/01 Python
python输出决策树图形的例子
2019/08/09 Python
使用TensorFlow对图像进行随机旋转的实现示例
2020/01/20 Python
PyQt5中QSpinBox计数器的实现
2021/01/18 Python
KIKO美国官网:意大利的平价彩妆品牌
2017/05/16 全球购物
展会邀请函范文
2014/01/26 职场文书
父母对孩子的寄语
2014/04/09 职场文书
班委竞选演讲稿
2014/04/28 职场文书
诉讼财产保全担保书
2014/05/20 职场文书
业绩倒数第一的检讨书
2014/09/24 职场文书
乡村教师党员四风问题对照检查材料思想汇报
2014/10/08 职场文书
党的群众路线专项整治方案
2014/11/03 职场文书
环保建议书范文
2015/09/14 职场文书
《从现在开始》教学反思
2016/02/16 职场文书
python如何在word中存储本地图片
2021/04/07 Python
Java无向树分析 实现最小高度树
2022/04/09 Javascript