猿问

跪求!是否存在通用的数组去重方法?

数组去重,很多时候都会用到,在具体项目中因为场景确定,很容易写出一个简单的去重方法,但大多是否具有针对性,没法适用于各类,一劳永逸。当然此处的场景所说的去重指的是去除内容大致相同的数据,不管是否同一个引用。
如下这段代码,如果希望输出的是[[1],{a:2},{a:1},[2]]
letobj={a:1};
letarr=[2];
lettest=[[1],[1],{a:2},{a:2},obj,obj,arr,arr];
Array.prototype.unique=function(){
...
}
console.log(test.unique());
通常我们利用Set和Array互转实现去重,但是该方式在判断引用类型时,并没那么给力,只有相同的引用才会被判定为相等。
console.log([...newSet(test)]);
//[[1],[1],{a:2},{a:2},{a:1},[2]];
如果采用对象的方式,对付普通的数据还好,碰上这种情况也是无能为力
Array.prototype.unique=function(){
varres=[];
varjson={};
for(vari=0;iif(!json[this[i]]){
res.push(this[i]);
json[this[i]]=true;
}
}
returnres;
}
console.log(test.unique());
//[[1],{a:2},[2]]非常神奇的是{a:1}竟然不见了
当然,如果采用极端点的方式只对引用类型的值先JSON.string(),再来做对比,好像可以,准确的说对简单且狭义的对象类型有效,因为File、Stack、HTMLElement、class、function等Object类型的等值判断没有json数据或字符串那般简单。
萧十郎
浏览 400回答 3
3回答

慕先生4543998

数组去重通用API要求就是写一个数组去重的API,第一个参数是一个数组,第二个参数是一个函数(对象数组去重的规则)。思路就是当它是数组的时候,直接用这个Set数据结构去重,如果是个对象数据的话,就新建一个Map,按照传入的函数返回的值,存入Map。这里用到了filter,它是用传入的函数测试所有的元素,并且返回所有通过测试的元素。function fn(arr,rule){     if(!rule){         return Array.from(new Set([...arr]));     }else{         const res=new Map();         return arr.filter((a)=>!res.has(rule(a))&&res.set(rule(a),1));     } }

慕村225694

看了lodash的源码迷迷糊糊的,还是用自己的方式来实现一把。部分人可能对题意所说的通用有着不一样的理解,所以觉得束手束脚有点难。此处的场景是确定,我的思路及实现如下,有人能提出点优化建议更好。//数组去重//deep不为空表示对引用类型的内容进行抽象判断Array.prototype.unique=function(deep){letarr=[...newSet(this)];deep&&deepUnique(arr);returnarr;}//深度去重,只对引用类型的数据进行再次内容对比functiondeepUnique(arr){letobjArr=[];arr.forEach((item,i)=>{if(['object','function'].includes(typeofitem)){objArr.unshift({idx:i,val:item});}})if(objArr.length=0;i--){if(['object','function'].includes(typeofarr[i])){objArr.some((item,idx)=>{if((item.idxval0[k]);letarr1=keys1.map(k=>val1[k]);res=isSameArray(arr0,arr1);}break;case'Array':res=isSameArray(val0,val1);break;case'Function':res=val0.toString()===val1.toString();break;case'Error':res=val0.stack===val1.stack;break;default:break;}returnres;}//是否相同的类型functionisSameType(val0,val1){lettype=false;if(val0.constructor==val1.constructor){letarr=val0.constructor.toString().substr(0,100).split('');type=arr[0]==='function'?arr[1].slice(0,-2):arr[1];}returntype;}//数组的值是否相同functionisSameArray(arr0,arr1){if(arr0.length!==arr1.length)returnfalse;letsame=true;for(leti=0;i

慕莱坞森

首先谈下我的理解,不可能有一劳永逸的方法。同意楼上去除复杂引用类型本身就是一个高度自定化的功能,需要自身去定义,按你的说法,1.待去重数组内的类型是不确定的2.不同的类型,甚至你自己定义的class,都有不同的"相等"的含义,比如定义user的类,只需id一样。在java中,判断对象相等需要重写equals和hashCode方法,equals返回true就是相等了,现在连类都未知,怎么去实现它的equals方法呢?ps:感觉实际开发中这种包罗万象的数组存在的可能性微乎其微,可以参考下lodash的unionWith函数_.unionWith([arrays],[comparator])varobjects=[{'x':1,'y':2},{'x':2,'y':1}];varothers=[{'x':1,'y':1},{'x':1,'y':2}];_.unionWith(objects,others,_.isEqual);//=>[{'x':1,'y':2},{'x':2,'y':1},{'x':1,'y':1}]把判断是否相等的代码comparator作为参数,如果有多种类型,就在comparator里面加个类型判断就好了。
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答