利用Distinct()内置方法对List集合的去重问题详解
前言
成都创新互联公司专注于遂川网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供遂川营销型网站建设,遂川网站制作、遂川网页设计、遂川网站官网定制、微信平台小程序开发服务,打造遂川网络公司原创品牌,更为您提供遂川网站排名全网营销落地服务。
说到对集合去重处理,第一时间想到的肯定是Linq的Distinct扩展方式,对于一般的值类型集合去重,很好处理,直接list.Distinct()即可。但是如果想要对一个引用类型的集合去重(属性值都相同就认为重复),就会发现,直接Distinct()是不行的
先来看看泛型链表 List
public class List
: IList , ICollection , IList, ICollection, IReadOnlyList , IReadOnlyCollection , IEnumerable , IEnumerable
可见它实现了 IEnumerable
使用这个方法时要注意:
(1)该方法并不会改变原来的链表;
(2)该方法返回一个对象(假设叫做dis),通过该对象可以枚举原链表中的非重复元素,但是并没有把非重复元素复制一份到新的对象中(连签拷贝也没有)
(3)由于(2),在枚举dis时,始终是依赖于原有链表,所以如果在获得dis后,又更新了原有链表,那么使用dis枚举将会使用原有链表的最新状态。
var list=new List()///表明具有重复值得集合
有时候Distinct()不能对引用类型去重时 我们就要自定义了 自定义代码如下:
public class User { public int Id { get; set; } public string Name { get; set; } } var list = new List() { new User() { Id = 1, Name = "张三" } , new User() { Id = 1, Name = "张三" } , new User() { Id = 3, Name = "李四" } , }; var newList1 = list.Distinct().ToList();
运行上述代码会发现,并不是预期想要的结果,newList1还是有3个元素。之所以会产生这样的结果,是因为Distinct()是通过使用默认的相等比较器对值进行比较返回序列中的非重复元素。对于值类型,默认的相等比较器是比较值是否相等,对于引用类型,默认的相等比较器是比较对象的引用地址,所以上述例子中即使属性值都相同,也不能去重。
IEqualityComparer
聪明的我们,很容易就能发现,Linq已经为我们重载了一个去重方法,可以满足我们的需求:
public static IEnumerableDistinct (this IEnumerable source, IEqualityComparer comparer);
重载的这个方法,多提供了一个参数IEqualityComparer
public class UserComparer : IEqualityComparer{ public bool Equals(User x, User y) { return x.Id == y.Id && x.Name == y.Name; } public int GetHashCode(User obj) { return obj.ToString().GetHashCode(); } }
IEqualityComparer
ar newList2 = list.Distinct(new UserComparer()).ToList();
甚至我们还可以实现只要某个属性相同就认为重复的效果,只需要在Equals方法按想要比较方式进行处理即可
延伸思考
Distinct的重载方法,基本已经能够满足我们的各式各样的去重需求了,但是想来想去,还是觉得有点别扭,那就是如果有类似的去重需求,我们都要新增一个类去实现IEqualityComparer
public class LambdaComparer: IEqualityComparer { private readonly Func _lambdaComparer; private readonly Func _lambdaHash; public LambdaComparer(Func lambdaComparer) : this(lambdaComparer, EqualityComparer .Default.GetHashCode) { } public LambdaComparer(Func lambdaComparer, Func lambdaHash) { if (lambdaComparer == null) throw new ArgumentNullException("lambdaComparer"); if (lambdaHash == null) throw new ArgumentNullException("lambdaHash"); _lambdaComparer = lambdaComparer; _lambdaHash = lambdaHash; } public bool Equals(T x, T y) { return _lambdaComparer(x, y); } public int GetHashCode(T obj) { return _lambdaHash(obj); } }
很巧妙的采用了泛型委托的方式,实现只需要定义一个类实现IEqualityComparer
var newList3 = list.Distinct(new LambdaComparer((a, b) => a.Id == b.Id && a.Name == b.Name, obj => obj.ToString().GetHashCode())).ToList();
是不是很熟悉的写法,想怎么比较就怎么比较,方便快捷,不需要定义那么多类去实现接口,目的达到。Linq中有很多扩展方法,都会用到IEqualityComparer
参考资料
1、https://www.jb51.net/article/162602.htm
2、https://ask.helplib.com/c-Sharp/post_1277383
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对创新互联的支持。
标题名称:利用Distinct()内置方法对List集合的去重问题详解
本文链接:http://cdiso.cn/article/iicsho.html