CombatKarl
CombatKarl

Reputation: 11

Searching 2 different Lists via Linq

I have 2 different IEnumerables:

IEnumerable<TypeA> ListA & IEnumerable<TypeB> ListB

Both types have the property called "PersString".

My goal is to get for each item in ListA the corresponding items of ListB with the same "PersString".

I started with a ForEach-Loop in ListA nesting a ForEach-Loop of ListB and checking if "PersString" of the ListA-item matches the "PersString" of the ListB-item.

Is there a more efficient way of coding using Linq ?

Thank you.

Upvotes: 1

Views: 321

Answers (3)

BionicCode
BionicCode

Reputation: 28988

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

Upvotes: 1

Vikram Bose
Vikram Bose

Reputation: 3365

Join is more efficient way

var result = from x in ListA
                     join y in ListB
                on x.PersString equals y.PersString
                     select new {x,y};

Upvotes: 0

Tim Schmelter
Tim Schmelter

Reputation: 460158

Is there a more efficient way of coding using Linq ?

Yes, you can join them. In Linq-To-Object this is (much) more efficient:

var query = from a in ListA 
            join b in ListB on a.PersString equals b.PersString
            select (A: a, B: b);

Upvotes: 2

Related Questions