如何比较C#中的两个列表并仅保留没有重复项的项?
这是两个列表:
var list1 = new List { new UserGroupMap { UserId = "1", GroupId = "1", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, new UserGroupMap { UserId = "1", GroupId = "2", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, new UserGroupMap { UserId = "1", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, new UserGroupMap { UserId = "2", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"} }; var list2 = new List { new UserGroupMap { UserId = "1", GroupId = "1", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, new UserGroupMap { UserId = "1", GroupId = "2", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, new UserGroupMap { UserId = "1", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, new UserGroupMap { UserId = "2", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, new UserGroupMap { UserId = "4", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, new UserGroupMap { UserId = "3", GroupId = "3", FormGroupFlag = "1", GroupDescription = "desc1", GroupName = "g1"}, };
现在我想要的是获得一个没有重复的列表,基本上比较list1和list2只返回重复的项目。
根据示例,它应返回的是列表2中的最后两项,因为它们不在list1中。
试试这个
list2.Except(list1).Concat(list1.Except(list2));
基本上,任务可以通过使用Linq解决
var Result = list1.Concat(list2).Except(list1.Intersect(list2));
但是,这可能需要UserGroupMap
以合适的方式实现IEquatable
接口,除非UserGroupMap
是一个struct
。 如果由于某种原因无法实现IEquatable
,则可以使用以自定义比较作为参数的Except
的重载 ,以及将自定义比较作为参数的Intersect
的重载 。
应该返回的是列表2中的最后两项,因为它们不在list1中。
更新如果您不能使用LINQ,您可以使用HashSet
来搜索和删除重复项。 你必须覆盖GetHashCode
和Equals
(或实现IEquatable
我所做的):
public class UserGroupMap : IEquatable { public string UserId {get;set;} public string GroupId { get; set; } public string FormGroupFlag { get; set; } public string GroupDescription { get; set; } public string GroupName { get; set; } public override int GetHashCode() { unchecked { int hash = 17; hash = hash * 23 + (UserId ?? "").GetHashCode(); hash = hash * 23 + (GroupId ?? "").GetHashCode(); hash = hash * 23 + (FormGroupFlag ?? "").GetHashCode(); hash = hash * 23 + (GroupDescription ?? "").GetHashCode(); hash = hash * 23 + (GroupName ?? "").GetHashCode(); return hash; } } public bool Equals(UserGroupMap other) { if(other == null) return false; if(Object.ReferenceEquals(this, other)) return true; return this.UserId == other.UserId && this.GroupId == other.GroupId && this.FormGroupFlag == other.FormGroupFlag && this.GroupDescription == other.GroupDescription && this.GroupName == other.GroupName; } }
现在很简单:
var uniqueInList2 = new HashSet(list2); uniqueInList2.ExceptWith(list1);
结果: list2
两个所需对象。
请注意,此方法还会从list2
删除重复项,我不确定是否需要。
老答案:
var onlyInTwo = list2 .Where(x => !list1.Any(x2 => x.UserId == x2.UserId && x.FormGroupFlag == x2.FormGroupFlag && x.GroupDescription == x2.GroupDescription && x.GroupName == x2.GroupName));
您还可以实现自定义IEqalityComparer
,可以在Enumerable.Except
。 然后它简单而有效:
var onlyInTwo = list2.Except(list1, new UserGroupMapComparer());
另一种方法是让UserGroupMap
重写Equals
和GetHashCode
或实现IEquatable
接口。
计算机不知道如何比较自定义类实例。 您有一些选择,其中之一是创建自己的比较器,必须实现IEqualityComparer
接口:
sealed class MyComparer : IEqualityComparer { public bool Equals(UserGroupMap x, UserGroupMap y) { if (x == null) return y == null; else if (y == null) return false; else return x.UserId.Equals(y.UserId) && x.GroupId.Equals(y.GroupId) && x.FormGroupFlag.Equals(y.FormGroupFlag) && x.GroupDescription.Equals(y.GroupDescription) && x.GroupName.Equals(y.GroupName); } public int GetHashCode(UserGroupMap obj) { unchecked { int hash = 17; hash = hash * 23 + (obj.UserId ?? "").GetHashCode(); hash = hash * 23 + (obj.GroupId ?? "").GetHashCode(); hash = hash * 23 + (obj.FormGroupFlag ?? "").GetHashCode(); hash = hash * 23 + (obj.GroupDescription ?? "").GetHashCode(); hash = hash * 23 + (obj.GroupName ?? "").GetHashCode(); return hash; } } }
然后使用System.Linq
命名空间中的Except()
通过使用默认的相等比较器来查找两个序列的差异:
var result = list2.Except(list1, new MyComparer()).ToList();
这个问题不清楚你是否想要:
1:list2中不在list1中的结果,如小样本集示例中所示:
应该返回的是列表2中的最后两项,因为它们不在list1中
或2:如果要从两个列表中找到非重复项
获取没有重复项的列表
或者3:如果你想从两个列表中找到重复项
基本上比较list1和list2只返回重复的项目。
3:很简单,所以可能不是这样:
list1.Concat(list2).Duplicate(new UserGroupMap());
假设您已将IEqualityComparer
添加到UserGroupMap(或作为单独的比较器添加)。
1:已经回答了
2:没有回答,所以你走了:
var result = (from item in list1.Concat(list2) group item by new { item.UserId, item.GroupId, item.FormGroupFlag, item.GroupDescription, item.GroupName } into groups where groups.Count() == 1 select groups) .SelectMany(x => x);
即使您交换list1和list2的内容,这也将起作用。