In addition to Enumerable.Join
, LINQ offers the Enumerable.Intersect
method and since .NET 6 the more convenient and powerful Enumerable.IntersectBy
.
In case of Enumerable.Intersect
, more complex types require you to provide an IEqualityComparer<T>
implementation or let the data type itself implement IEquatable<T>
to define equality of this type.
Example Intersect
(Prior to .NET 6):
Does not support comparison of two sets of different type.
class Person : IEquatable<Person>
{
public bool Equals(Person p) => this.PersString == p?.PersString;
public override int GetHashCode() => HashCode.Combine(PersString);
public int ID { get; set; }
public string PersString { get; set; }
}
IEnumerable<Person> collectionA;
IEnumerable<Person> collectionB;
IEnumerable<Person> equalPersonInstances = collectionA.Intersect(collectionB);
// In case the compared type does not implement IEquatable, we would have to provide an IEqualityComparer
// IEnumerable<Person> equalMyTypeInstances = collectionA.Intersect(collectionB, new MyComparer());
Example IntersectBy
(.NET 6 and later):
Since .NET 6 we can use the ...By
methods to pass in a lambda expression or method group as equality comparer. In this case we call Enumeable.IntersectBy
, which supports to find the intersection of two sets of different type.
IEnumerable<PersonA> collectionA;
IEnumerable<PersonB> collectionB;
IEnumerable<PersonA> intersection = collectionA.IntersectBy(
collectionB.Select(personB => personB.PersString),
personA => personA.PersString);
Example Join
(using LINQ Enumerable
extension method)
For those who prefer to use the LINQ extension methods:
IEnumerable<PersonA> collectionA;
IEnumerable<PersonB> collectionB;
// The result is a set of ValueTuple
IEnumerable<(Person, PersonB)> intersection = collectionA.Join(
collectionB,
personA => personA.PersString,
personB => personB.PersString,
(personA, personB) => (personA, personB));