Compare Two Lists Via One Property Using LINQ

C#LinqListCollections

C# 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();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionColtechView Question on Stackoverflow
Solution 1 - C#AnirudhaView Answer on Stackoverflow
Solution 2 - C#ServyView Answer on Stackoverflow
Solution 3 - C#Bruno GozziView Answer on Stackoverflow
Solution 4 - C#HeinziView Answer on Stackoverflow
Solution 5 - C#Soumya DasView Answer on Stackoverflow