是否存在通用的数组去重方法?
数组去重,很多时候都会用到,在具体项目中因为场景确定,很容易写出一个简单的去重方法,但大多是否具有针对性,没法适用于各类,一劳永逸。
当然此处的场景所说的去重指的是去除内容大致相同的数据,不管是否同一个引用
。
如下这段代码,如果希望输出的是 [[1],{a:2},{a:1},[2]]
let obj = {a:1};
let arr = [2];
let test = [ [1], [1], {a:2}, {a:2}, obj, obj, arr, arr ];
Array.prototype.unique = function(){
...
}
console.log(test.unique());
通常我们利用Set和Array互转实现去重,但是该方式在判断引用类型时,并没那么给力,只有相同的引用才会被判定为相等。
console.log([...new Set(test)]);
// [[1],[1],{a:2},{a:2}, {a:1}, [2]];
如果采用对象的方式,对付普通的数据还好,碰上这种情况也是无能为力
Array.prototype.unique = function() {
var res = [];
var json = {};
for(var i = 0; i < this.length; i++){
if(!json[this[i]]){
res.push(this[i]);
json[this[i]] = true;
}
}
return res;
}
console.log(test.unique());
// [[1],{a:2},[2]] 非常神奇的是{a:1}竟然不见了
当然,如果采用极端点的方式只对引用类型的值先JSON.string()
,再来做对比,好像可以,准确的说对简单且狭义的对象类型有效,因为File、Stack、HTMLElement、class、function
等Object类型的等值判断没有json数据或字符串那般简单。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
去除复杂引用类型本身就是一个高度自定化的功能,如何定义去重,从机器角度出发,如果两个变量引用相同,那么他们就是重复的。如果比较的是两个对象,如何定义重复是一个依赖于功能需求的定义,比如两个引用对象里的常量相等,但引用不同能不能叫重复;引用相同但常量值不同能不能叫重复,这些是需要你自身去定义的。
这个可以看一下
lodash
的 baseUniq 源码有
array , iteratee, comparator
, 数组,迭代器,比较器3个参数这一个方法演化了
union, uniq, unionBy, uniqBy, unionWith, uniqWith
6个方法如果我们比较
[ { age: 1 }, { age: 1 } ]
是否重复可以 使用iteratee
:item => item.age
如果我们比较
[ { 'x': 1, 'y': 2 }, { 'x': 1, 'y': 2 } ]
是否重复可以 使用comparator
:(target, value) => target.x === value.x && target.y === value.y
(也可以用其他的方法,遍历,JSON.stringify
)首先谈下我的理解,不可能有一劳永逸的方法。
同意楼上去除复杂引用类型本身就是一个高度自定化的功能,需要自身去定义,按你的说法,
1.待去重数组内的类型是不确定的
2.不同的类型,甚至你自己定义的class,都有不同的"相等"的含义,比如定义user的类,只需id一样。
在java 中,判断对象相等需要重写equals和hashCode方法,equals返回true就是相等了,现在连类都未知,怎么去实现它的equals方法呢?
ps:
感觉实际开发中这种包罗万象的数组存在的可能性微乎其微,可以参考下lodash的unionWith 函数
_.unionWith([arrays], [comparator])
把判断是否相等的代码
comparator
作为参数,如果有多种类型,就在comparator
里面加个类型判断就好了。看了lodash的源码迷迷糊糊的,还是用自己的方式来实现一把。部分人可能对题意所说的通用有着不一样的理解,所以觉得束手束脚有点难。此处的场景是确定,我的思路及实现如下,有人能提出点优化建议更好。
测试结果如下