本文详细解析JavaScript中四种常见的数组去重方法,包括利用对象属性、indexOf查找位置、判断首次出现索引以及先排序后比较。通过生成不同规模的数据集进行基准测试,对比各方法在100至50000个元素下的执行耗时,揭示方法二、三在大数据量下的性能瓶颈,并给出效率排序建议。
引言与注意事项
网络上关于数组去重的实现方案层出不穷,本文重新梳理这些方法,旨在帮助开发者在熟悉一种方案后能回顾其他实现方式。同时,为了直观展示不同算法的性能差异,本文将先总结几种较为典型的去重思路,随后统一进行效率测试,以找出执行速度最快的方案。需要提醒的是,下文示例为了简化代码结构,直接修改了Array原型,在实际生产环境中,这种做法容易污染全局对象,建议谨慎使用。
四种去重方法详解
第一种方法的核心思路是利用对象属性的唯一性来过滤重复元素。
var n = [14,12,2,2,2,5,32,2,59,5,6,33,12,32,6];
Array.prototype.unique1 = function(){
var obj = {},
ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(!obj[this[i]]){
obj[this[i]] = 1;
ary.push(this[i]);
}
}
return ary.sort(function(a,b){return a - b});
}
console.log(n.unique1());
第二种方法通过遍历数组,利用indexOf查找元素在结果数组中是否存在,若不存在则添加。
var n = [14,12,2,2,2,5,32,2,59,5,6,33,12,32,6];
Array.prototype.unique2 = function(){
var ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(ary.indexOf(this[i]) == -1) ary.push(this[i]);
}
return ary.sort(function(a,b){return a - b});
}
console.log(n.unique2());
第三种方法与第二种类似,但其判断逻辑是检查当前元素在原数组中第一次出现的索引是否等于当前遍历的索引。
var n = [14,12,2,2,2,5,32,2,59,5,6,33,12,32,6];
Array.prototype.unique3 = function(){
var ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(this.indexOf(this[i]) == i) ary.push(this[i]);
}
return ary.sort(function(a,b){return a - b});
}
console.log(n.unique3());
第四种方法采用较为常规的策略:先对数组进行排序,然后遍历排序后的数组,比较相邻两个元素是否相等,从而剔除重复项。
var n = [14,12,2,2,2,5,32,2,59,5,6,33,12,32,6];
Array.prototype.unique4 = function(){
this.sort(function(a,b){return a - b});
var ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(this[i] !== this[i-1]) ary.push(this[i]);
}
return ary;
}
console.log(n.unique4());
性能测试与分析
接下来是本文的重点部分,即对上述几种方法的效率进行量化比较。为此,我们需要构建一个统一的计时函数来标准化测试流程。
首先,我们需要生成一个包含100个随机数字的测试数组。
Array.prototype.unique1 = function(){
var obj = {},
ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(!obj[this[i]]){
obj[this[i]] = 1;
ary.push(this[i]);
}
}
return ary.sort(function(a,b){return a - b});
}
Array.prototype.unique2 = function(){
var ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(ary.indexOf(this[i]) == -1) ary.push(this[i]);
}
return ary.sort(function(a,b){return a - b});
}
Array.prototype.unique3 = function(){
var ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(this.indexOf(this[i]) == i) ary.push(this[i]);
}
return ary.sort(function(a,b){return a - b});
}
Array.prototype.unique4 = function(){
this.sort(function(a,b){return a - b});
var ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(this[i] !== this[i-1]) ary.push(this[i]);
}
return ary;
}
function randomAry (n) {
var ary = [],i=0;
for(; i<n; i++){
ary.push(Math.ceil(Math.random()*10000));
}
console.log(ary)
return ary;
}
function useTime (fn) {
var start = new Date();
fn();
var end = new Date();
console.log('本次函數運行花了:' + (end - start) + '毫秒');
}
var ary = randomAry(100),
fn1 = function(){
ary.unique1()
},
fn2 = function(){
ary.unique2()
},
fn3 = function(){
ary.unique3()
},
fn4 = function(){
ary.unique4()
};
useTime(fn1);
useTime(fn2);
useTime(fn3);
useTime(fn4);
在Google Chrome浏览器环境下运行测试,初始结果如下。
方法一的执行耗时为0毫秒。
方法二的执行耗时为1毫秒。
方法三的执行耗时为0毫秒。
方法四的执行耗时为00毫秒。
可以看出,在现代浏览器中,这几种方法处理小规模数据时差异极小,性能均表现优异,无需过多纠结旧版浏览器的兼容性问题。
为了进一步验证性能差异,我们将测试数据量提升至1000个数字。
Array.prototype.unique1 = function(){
var obj = {},
ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(!obj[this[i]]){
obj[this[i]] = 1;
ary.push(this[i]);
}
}
return ary.sort(function(a,b){return a - b});
}
Array.prototype.unique2 = function(){
var ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(ary.indexOf(this[i]) == -1) ary.push(this[i]);
}
return ary.sort(function(a,b){return a - b});
}
Array.prototype.unique3 = function(){
var ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(this.indexOf(this[i]) == i) ary.push(this[i]);
}
return ary.sort(function(a,b){return a - b});
}
Array.prototype.unique4 = function(){
this.sort(function(a,b){return a - b});
var ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(this[i] !== this[i-1]) ary.push(this[i]);
}
return ary;
}
function randomAry (n) {
var ary = [],i=0;
for(; i<n; i++){
ary.push(Math.ceil(Math.random()*10000));
}
console.log(ary)
return ary;
}
function useTime (fn) {
var start = new Date();
fn();
var end = new Date();
console.log('本次函數運行花了:' + (end - start) + '毫秒');
}
var ary = randomAry(1000),
fn1 = function(){
ary.unique1()
},
fn2 = function(){
ary.unique2()
},
fn3 = function(){
ary.unique3()
},
fn4 = function(){
ary.unique4()
};
useTime(fn1);
useTime(fn2);
useTime(fn3);
useTime(fn4);
方法一:1-2毫秒
方法二:40-50毫秒
方法三:40-50毫秒
方法四:0-1毫秒
看看10000個數字(數據龐大,開始吃不消了,等個五六秒吧)
Array.prototype.unique1 = function(){
var obj = {},
ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(!obj[this[i]]){
obj[this[i]] = 1;
ary.push(this[i]);
}
}
return ary.sort(function(a,b){return a - b});
}
Array.prototype.unique2 = function(){
var ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(ary.indexOf(this[i]) == -1) ary.push(this[i]);
}
return ary.sort(function(a,b){return a - b});
}
Array.prototype.unique3 = function(){
var ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(this.indexOf(this[i]) == i) ary.push(this[i]);
}
return ary.sort(function(a,b){return a - b});
}
Array.prototype.unique4 = function(){
this.sort(function(a,b){return a - b});
var ary = [],
i= 0,
len = this.length;
for(; i<len; i++){
if(this[i] !== this[i-1]) ary.push(this[i]);
}
return ary;
}
function randomAry (n) {
var ary = [],i=0;
for(; i<n; i++){
ary.push(Math.ceil(Math.random()*10000));
}
console.log(ary)
return ary;
}
function useTime (fn) {
var start = new Date();
fn();
var end = new Date();
console.log('本次函數運行花了:' + (end - start) + '毫秒');
}
var ary = randomAry(10000),
fn1 = function(){
ary.unique1()
},
fn2 = function(){
ary.unique2()
},
fn3 = function(){
ary.unique3()
},
fn4 = function(){
ary.unique4()
};
useTime(fn1);
useTime(fn2);
useTime(fn3);
useTime(fn4);
由于数据量增大,单次测试结果可能存在波动,建议多次刷新页面取平均值以获得更准确的参考。
在1000个数据量的测试中,方法一的执行耗时为10毫秒。
方法二的执行耗时显著增加,达到1258毫秒。
方法三的执行耗时同样较高,为2972毫秒。
方法四的执行耗时仅为5毫秒,表现依然稳定。
原本计划测试更大规模的数据集,但当数据量达到十万级别时,页面内存溢出导致崩溃,无法继续运行。
尝试将数据量调整为五万时,同样出现了页面崩溃的情况。
鉴于上述限制,我们仅基于现有测试结果进行分析。
综合一万以内数据的对比结果可以看出,随着数据量的增加,方法一和方法四的耗时呈线性缓慢增长,而方法二和方法三的效率急剧下降,性能表现令人担忧。
根据测试数据得出的效率排序为:方法四 > 方法一 > 方法二 > 方法三。
从代码实现逻辑来看,推荐顺序为:先排序再比较前后元素 > 利用对象属性判断 > 利用indexOf查找位置 > 判断首次出现索引与当前位置是否一致。
以上就是本文的全部内容,希望这些关于数组去重方法及效率对比的分析能对您的学习或工作有所帮助。如果您觉得有用,欢迎支持本站。