如何比较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来搜索和删除重复项。 你必须覆盖GetHashCodeEquals (或实现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重写EqualsGetHashCode或实现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的内容,这也将起作用。