Reputation: 3761
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 what I want to happen is to get a list that doesn't have duplicates, basically compare list1 and list2 return only the items that are duplicate.
based from the sample what it should return are the last two items from list 2 since they are not in list1.
Upvotes: 5
Views: 2446
Reputation: 26645
Computer doesn't know how to compare your custom class instances. You have some choices and one of them is to create your own comparer which must implement 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 of two sequences by using the default equality comparer:
var result = list2.Except(list1, new MyComparer()).ToList();
Upvotes: 1
Reputation: 28611
It's not clear from the question if you want:
1: results from list2 that aren't in list1, as in the small sample set example:
what it should return are the last two items from list 2 since they are not in list1
or 2: if you want to find the non-duplicates from both lists
to get a list that doesn't have duplicates
or 3: if you want to find the duplicates from both lists
basically compare list1 and list2 return only the items that are duplicate.
3: is trivial, so probably not that:
list1.Concat(list2).Duplicate(new UserGroupMap());
Assuming you've added IEqualityComparer
to your UserGroupMap (or added as a separate comparer).
1: has been answered
2: has not been answered, so here 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);
this will then work even if you swap the content of list1 and list2.
Upvotes: 0
Reputation: 460208
what it should return are the last two items from list 2 since they are not in list1.
Update If you can't use LINQ you could use a HashSet<T>
to search and remove duplicates. You have to 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 it's easy:
var uniqueInList2 = new HashSet<UserGroupMap>(list2);
uniqueInList2.ExceptWith(list1);
Result: your two desired objects from list2
.
Note that this approach also removes duplicates from list2
, i'm not sure if that's desired.
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 could also implement a custom IEqalityComparer<UserGroupMap>
which can be used for example in Enumerable.Except
. Then it's simple and efficient:
var onlyInTwo = list2.Except(list1, new UserGroupMapComparer());
Another way is let UserGroupMap
override Equals
and GetHashCode
or to implement the IEquatable<UserGroupMap>
interface.
Upvotes: 1
Reputation: 17605
Basically, the task can be solved with Linq by using
var Result = list1.Concat(list2).Except(list1.Intersect(list2));
however this probably requires UserGroupMap
to implement the interface IEquatable<UserGroupMap>
in a suitable way, unless UserGroupMap
is a struct
. If implementation of IEquatable<UserGroupMap>
for some reason is impossible, the overload of Except
which takes a custom comparison as an argument can be used, as well as the overload of Intersect
which takes a custom comparison as an argument.
Upvotes: 4