How to compare two <object> lists in C # and save only items that don't have duplicates?

Here are two lists:

 var list1 = new List<UserGroupMap> { 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<UserGroupMap> { 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"}, }; 

Now I want to get a list that has no duplicates, basically compare list1 and list2 to return only duplicates.

based on the sample, what it should return is the last two elements from list 2, since they are not in list1.

+5
source share
5 answers

try it

 list2.Except(list1).Concat(list1.Except(list2)); 
+5
source

In principle, the problem can be solved using Linq using

 var Result = list1.Concat(list2).Except(list1.Intersect(list2)); 

however, this probably requires UserGroupMap implement the IEquatable<UserGroupMap> interface accordingly if UserGroupMap not a struct . If for some reason the implementation of IEquatable<UserGroupMap> not possible, the Except overload , which takes an arbitrary comparison as an argument, can be used, as well as the Intersect overload , which takes an arbitrary comparison as an argument.

+4
source

what he must return are the last two items from list 2, since they are not in list1.

Refresh . If you cannot use LINQ, you can use HashSet<T> to find and remove duplicates. You must override GetHashCode and Equals (or implement IEquatable<T> what I did):

 public class UserGroupMap : IEquatable<UserGroupMap> { 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; } } 

Now easy:

 var uniqueInList2 = new HashSet<UserGroupMap>(list2); uniqueInList2.ExceptWith(list1); 

Result: two of your desired objects from list2 .

Note that this approach also removes duplicates from list2 , I'm not sure if this is necessary.


Old answer:

 var onlyInTwo = list2 .Where(x => !list1.Any(x2 => x.UserId == x2.UserId && x.FormGroupFlag == x2.FormGroupFlag && x.GroupDescription == x2.GroupDescription && x.GroupName == x2.GroupName)); 

You can also implement a custom IEqalityComparer<UserGroupMap> , which can be used, for example, in Enumerable.Except . Then it is simple and effective:

 var onlyInTwo = list2.Except(list1, new UserGroupMapComparer()); 

Another way: UserGroupMap override Equals and GetHashCode or implement IEquatable<UserGroupMap> interface.

+1
source

The computer does not know how to compare your custom class instances. You have a choice, and one of them is to create your own comparator, which should implement the IEqualityComparer<T> interface:

 sealed class MyComparer : IEqualityComparer<UserGroupMap> { 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; } } } 

And then use Except() from the System.Linq namespace to find the difference between the two sequences using the default equality resolver:

 var result = list2.Except(list1, new MyComparer()).ToList(); 
+1
source

It is not clear from the question whether you want to:

1: results from list2 that are not in list1, as in the example with a small example:

what it should return is the last two elements from list 2, since they are not in list1

or 2: if you want to find non-duplicates from both lists

to get a list that has no duplicates

or 3: if you want to find duplicates from both lists

basically compare list1 and list2 to return only duplicates.

3: trivial, so probably not so:

 list1.Concat(list2).Duplicate(new UserGroupMap()); 

Assuming you added IEqualityComparer to your UserGroupMap (or added as a separate comparator).

1: the answer was given

2: there was no answer, so you go:

 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); 

then this will work even if you replace the contents of list1 and list2.

0
source

All Articles