Reputation: 2028
I've got a class:
class ThisClass
{
private string a {get; set;}
private string b {get; set;}
}
I would like to use the Intersect and Except methods of Linq, i.e.:
private List<ThisClass> foo = new List<ThisClass>();
private List<ThisClass> bar = new List<ThisClass>();
Then I fill the two lists separately. I'd like to do, for example (and I know this isn't right, just pseudo code), the following:
foo[a].Intersect(bar[a]);
How would I do this?
Upvotes: 27
Views: 38839
Reputation: 1
You can try the following. This is a lambda expression in which we define the item which is a ThisClass variable and the equality as an internal lambda expression between foo and bar. In where clause we get the elements that satisfy the equality creteria depending on field a, and because this return an anonymous type of class we select the q.item which represents all the items of ThisClass that satisfy the equality and gives type of IEnumerable.
IEnumerable<ThisClass> Intersection =
foo.Select(x => new
{
item = x,
equality = bar.Any(y => y.a.Equals(x.a))
}).Where(w => w.equality).Select(q => q.item);
Upvotes: -1
Reputation: 21
I know this is old but couldn't you also just override the Equals & GetHashCode on the class itself?
class ThisClass
{
public string a {get; set;}
private string b {get; set;}
public override bool Equals(object obj)
{
// If you only want to compare on a
ThisClass that = (ThisClass)obj;
return string.Equals(a, that.a/* optional: not case sensitive? */);
}
public override int GetHashCode()
{
return a.GetHashCode();
}
}
Upvotes: 0
Reputation: 810
Not sure of the speed of this compared to intersect and compare but how about:
//Intersect
var inter = foo.Where(f => bar.Any(b => b.a == f.a));
//Except - values of foo not in bar
var except = foo.Where(f => !bar.Any(b => b.a == f.a));
Upvotes: 7
Reputation: 236308
Maybe
// returns list of intersecting property 'a' values
foo.Select(f => f.a).Intersect(bar.Select(b => b.a));
BTW property a
should be public.
Upvotes: 39
Reputation: 14328
If you want a list of a single property you'd like to intersect then all the other pretty LINQ solutions work just fine.
BUT! If you'd like to intersect on a whole class though and as a result have a List<ThisClass>
instead of List<string>
you'll have to write your own equality comparer.
foo.Intersect(bar, new YourEqualityComparer());
same with Except
.
public class YourEqualityComparer: IEqualityComparer<ThisClass>
{
#region IEqualityComparer<ThisClass> Members
public bool Equals(ThisClass x, ThisClass y)
{
//no null check here, you might want to do that, or correct that to compare just one part of your object
return x.a == y.a && x.b == y.b;
}
public int GetHashCode(ThisClass obj)
{
unchecked
{
var hash = 17;
//same here, if you only want to get a hashcode on a, remove the line with b
hash = hash * 23 + obj.a.GetHashCode();
hash = hash * 23 + obj.b.GetHashCode();
return hash;
}
}
#endregion
}
Upvotes: 41
Reputation: 14700
What exactly is the desired effect? Do you want to get a list of strings composed of all the a
's in your classes, or a list of ThisClass
, when two ThisClass
instances are identified via unique values of a
?
If it's the former, the two answers from @lazyberezovksy and @Tilak should work. If it's the latter, you'll have to override IEqualityComparer<ThisClass>
or IEquatable<ThisClass>
so that Intersect
knows what makes two instances of ThisClass
equivalent:
private class ThisClass : IEquatable<ThisClass>
{
private string a;
public bool Equals(ThisClass other)
{
return string.Equals(this.a, other.a);
}
}
then you can just call:
var intersection = foo.Intersect(bar);
Upvotes: -1
Reputation: 1435
You should create IEqualityComparer. You can pass the IEqualityComparer to Intersect() method. This will help you get List(which intersect with bar) easier.
var intersectionList = foo.Intersect(bar, new ThisClassEqualityComparer()).ToList();
class ThisClassEqualityComparer : IEqualityComparer<ThisClass>
{
public bool Equals(ThisClass b1, ThisClass b2)
{
return b1.a == b2.a;
}
public int GetHashCode(Box bx)
{
// To ignore to compare hashcode, please consider this.
// I would like to force Equals() to be called
return 0;
}
}
Upvotes: -3