locked
Using linq to find the intersection of two lists but each list contains different classes but I want to compare two of their properties together RRS feed

  • Question

  • Hello,

     

    I have two different classes lets call them A and B.  Both classes have a string property called Name.  I have two lists ListA which contains a bunch of A cobjects and ListB which contains a bunch of B objects.

     

    I would like to use linq statment and make a new List (ListA2) that contains all of the A objects in ListA that share the same name with the objects in ListB.

    I was initially thinking Intersect could help but doesn't that require both lists using the same objects....


    • Edited by Lavagin Wednesday, September 7, 2011 12:28 PM
    Wednesday, September 7, 2011 12:21 PM

Answers

  • This is how you can do it:

        class Program
        {
            static void Main(string[] args)
            {
                List<Class1> list1 = new List<Class1>();
                List<Class2> list2 = new List<Class2>();
                list1.Add(new Class1 { Name = "name1" });
                list1.Add(new Class1 { Name = "name2" });
                list2.Add(new Class2 { Name = "name2" });
                list2.Add(new Class2 { Name = "name3" });
               
                var distItems = list1.Select(s1 => new Class1 { Name = s1.Name }).Where(w => list2.Select(s2 => s2.Name).Contains(w.Name)).ToList();
            }
        }
    
        class Class1
        {
            public string Name;
        }
    
        class Class2
        {
            public string Name;
        }
    



    Mitja
    • Marked as answer by Lavagin Wednesday, September 7, 2011 2:30 PM
    Wednesday, September 7, 2011 12:55 PM

All replies

  • This is how you can do it:

        class Program
        {
            static void Main(string[] args)
            {
                List<Class1> list1 = new List<Class1>();
                List<Class2> list2 = new List<Class2>();
                list1.Add(new Class1 { Name = "name1" });
                list1.Add(new Class1 { Name = "name2" });
                list2.Add(new Class2 { Name = "name2" });
                list2.Add(new Class2 { Name = "name3" });
               
                var distItems = list1.Select(s1 => new Class1 { Name = s1.Name }).Where(w => list2.Select(s2 => s2.Name).Contains(w.Name)).ToList();
            }
        }
    
        class Class1
        {
            public string Name;
        }
    
        class Class2
        {
            public string Name;
        }
    



    Mitja
    • Marked as answer by Lavagin Wednesday, September 7, 2011 2:30 PM
    Wednesday, September 7, 2011 12:55 PM
  • I think that is close to what I would like.  But is there a way to do that without making a new Class1 for each one?
    Wednesday, September 7, 2011 1:26 PM
  • Actually playing around with it fixes what I was trying to fix!  Thanks!
    Wednesday, September 7, 2011 2:30 PM
  • There is no need to generate the list of names in list2 each iteration (unless Linq is smart enough to pull that out on its own, which I don't think it does).

     

    var names = list2.Select(item => item.Name);
    var result = list1.Where(item => names.Contains(item.Name));
    


    It would also scale better at large values if 'names' was a set and not an enumeration.

     

    All in all if performance is an issue I wouldn't use Linq at all though, as you need to re-create structures in order to make it work.

    Wednesday, September 7, 2011 2:33 PM
  • You can dot his with a pretty simple LINQ query. Just join the two together, and only select the items that have a match.

    var distItems = from list1Item in list1
                           join list2Item in list2 on list1Item.Name equals list2Item.Name
                           where (list2Item != null)
                           select list1Item;
                           
    



    Check out My Blog for tech news, development tips, and other information for geeks like me.
    • Proposed as answer by cranfan Friday, January 3, 2020 4:45 AM
    Wednesday, September 7, 2011 2:36 PM
  • where (list2Item != null)

    If list2Item is null, the query throws an exception. Here is not the right location to test this.
    Thursday, September 8, 2011 10:26 AM
  • where (list2Item != null)

    If list2Item is null, the query throws an exception. Here is not the right location to test this.

    I'm not sure what exception you're seeing. It works correctly for me - though that line isn't actually required. Because the join creates an inner join, nothing will come back where list2Item == null, so the condition is never false. I should have left it out, since it's redundant. Even so, having the line there doesn't hurt anything. Try this code for example:

     

    var list1 = new List<ListItemTest>
                                {
                                    new ListItemTest {Name = "A"}, 
                                    new ListItemTest {Name = "B"}, 
                                    new ListItemTest {Name = "C"}, 
                                    new ListItemTest {Name = "D"}, 
                                    new ListItemTest {Name = "E"}
                                };
                var list2 = new List<ListItemTest>
                                {
                                    new ListItemTest {Name = "B"}, 
                                    new ListItemTest {Name = "F"}, 
                                    new ListItemTest {Name = "D"}, 
                                    new ListItemTest {Name = "C"}, 
                                    new ListItemTest {Name = "G"}
                                };
    
                var distItems = from list1Item in list1
                                join list2Item in list2 on list1Item.Name equals list2Item.Name
                                where (list2Item != null)
                                select list1Item;
    

    The only thing I can think of is if you're using a database back-end instead of lists, but even then I don't think the line would cause any problems, but I haven't set up a test case to make sure.

    EDIT: Forgot to include my simple ListItemTest class:

            public class ListItemTest
            {
                public string Name { get; set; }
            }
    



    Check out My Blog for tech news, development tips, and other information for geeks like me.
    Thursday, September 8, 2011 1:16 PM
  • The only way for list2Item to be null is if you actually have a null value in list2. That would throw an exception when trying to evaluate list2Item.Name.
    Monday, September 12, 2011 12:48 PM