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?
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.
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
}
foo.Select(x=>x.a).Intersect(bar.Select(x=>x.a))
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));
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);
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();
}
}
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;
}
}
来源:https://stackoverflow.com/questions/10633375/c-sharp-linq-intersect-except-with-one-part-of-object