数组去重,很多时候都会用到,在具体项目中因为场景确定,很容易写出一个简单的去重方法,但大多是否具有针对性,没法适用于各类,一劳永逸。当然此处的场景所说的去重指的是去除内容大致相同的数据,不管是否同一个引用。如下这段代码,如果希望输出的是[[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;i
3 回答
慕先生4543998
TA贡献1条经验 获得超1个赞
数组去重通用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
TA贡献1880条经验 获得超4个赞
看了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<=1)return;for(leti=arr.length-1;i>=0;i--){if(['object','function'].includes(typeofarr[i])){objArr.some((item,idx)=>{if((item.idxobjArr.splice(idx,1);//缩短遍历长度arr.splice(i,1);//移除重复数据returntrue;}})}}}//是否内容相同functionisSameObj(val0,val1){letres=false;lettype=isSameType(val0,val1);if(!type)returnres;switch(type){case'HTMLDivElement':res=val0.outerHTML===val1.outerHTML;break;case'File':res=JSON.stringify(val0)===JSON.stringify(val1);break;case'class':case'Object':letkeys0=Object.keys(val0);letkeys1=Object.keys(val1);if(JSON.stringify(keys0)===JSON.stringify(keys1)){letarr0=keys0.map(k=>val0[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;iif(typeofarr0[i]!==typeofarr1[i]){//类型不同 same=false;break;}if(arr0[i]&&arr1[i]&&['object','function'].includes(typeofarr0[i])){//非空引用类型if(!isSameObj(arr0[i],arr1[i])){same=false;break;}}elseif((arr0[i]!==arr1[i])){if(!((typeofarr0[i]==='number')&&isNaN(arr0[i])&&isNaN(arr1[i]))){//除了NaN!=NaN的情况same=false;break;}}}returnsame;}测试结果如下letobj={a:1};letarr=[2];lettest=[[1],[1],{a:2},{a:2},obj,obj,arr,arr];console.log(test.unique());//[[1],[1],{a:2},{a:2},{a:1},[2]]console.log(test.unique(true));//[[1],{a:2},{a:1},[2]]
慕莱坞森
TA贡献1810条经验 获得超4个赞
首先谈下我的理解,不可能有一劳永逸的方法。同意楼上去除复杂引用类型本身就是一个高度自定化的功能,需要自身去定义,按你的说法,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里面加个类型判断就好了。
添加回答
举报
0/150
提交
取消