Compare Two Lists Via One Property Using LINQ
C#LinqListCollectionsC# Problem Overview
Say I have the following:
class Widget1{
public int TypeID { get; set; }
public string Color { get; set; }
}
class Widget2
{
public int TypeID { get; set; }
public string Brand { get; set; }
}
private void test()
{
List<Widget1> widgets1 = new List<Widget1>();
List<Widget2> widgets2 = new List<Widget2>();
List<Widget1> widgets1_in_widgets2 = new List<Widget1>();
//some code here to populate widgets1 and widgets2
foreach (Widget1 w1 in widgets1)
{
foreach (Widget2 w2 in widgets2)
{
if (w1.TypeID == w2.TypeID)
{
widgets1_in_widgets2.Add(w1);
}
}
}
}
I am using two foreach loops to compare the lists by TypeID to populate a third list. Is there any other way using LINQ to compare these two lists via the TypeID? Perhaps using Interstect or some other function?
C# Solutions
Solution 1 - C#
You can do this
widgets2.Where(y=>widget1.Any(z=>z.TypeID==y.TypeID));
Solution 2 - C#
What you want here is a Join
.
var widgets1_in_widgets2 = from first in widgest1
join second in widgets2
on first.TypeID equals second.TypeID
select first;
Intersect
can be more or less thought of as a special case of Join
where the two sequences are of the same type, and can thus be applied for equality instead of needing a projection for each type to generate a key to compare. Given your case, Intersect
isn't an option.
If a particular ID is duplicated in your second set and you don't want the item to be duplicated in the results then you can use a GroupJoin
instead of a Join
:
var widgets1_in_widgets2 = from first in widgest1
join second in widgets2
on first.TypeID equals second.TypeID
into matches
where matches.Any()
select first;
Solution 3 - C#
I like this solution because it is simple to read in the code.
bool result = firstList.All(o => secondList.Any(w => w.Prop1 == o.Prop1 && w.Prop2 == o.Prop2));
See the full example in fiddle: Fiddle example comparation
Solution 4 - C#
Join has the drawback that your results might be duplicated if widgets1 or widgets2 contains elements with the same TypeID more than one (which also applies to your original code, by the way).
The following will do exactly what you want: Return all elements from widgets1 for which an element with a corresponding TypeID exists in widgets2.
widgets1_in_widgets2 = (from w1 in widgets1
where widgets2.Any(w2 => w1.TypeID == w2.TypeID)
select w1).ToList()
Solution 5 - C#
Try using overload of "Where"
var isMatch = !widgets1.Where((w1, index) => w1.TypeId == widgets2[index].TypeId)).Any();