Home > database >  What is the fastest way to join two lists using linq query syntax?
What is the fastest way to join two lists using linq query syntax?

Time:10-07

I would like to understand how to join two lists using 'contains' instead 'equals'. There are similar questions here on SO, but nothing seems to work. Here is my sample code, my aim is to get the student who does not belong to any classRoom:

        var a = new Student("A");
        var b = new Student("B");
        var c = new Student("C");
        var d = new Student("D");
        var e = new Student("E");
        var f = new Student("F");
        var students = new List<Student>() { a, b, c, d, e, f };

        var classRoomA = new ClassRoom();
        classRoomA.Students.Add(a);
        classRoomA.Students.Add(b);

        var classRoomB = new ClassRoom();
        classRoomB.Students.Add(c);
        classRoomB.Students.Add(d);

        var classRoomC = new ClassRoom();
        classRoomC.Students.Add(e);

        var classes = new List<ClassRoom> { classRoomA, classRoomB, classRoomC };

        //option A. This works
        var studentsWithoutClassRoom = students
            .Where(stu => !classes.Any(r => r.Students.Contains(stu)))
            .Select(s => s);

        //optionB .This in one of many options that
        //I have tried and it gives very interesting results
        var studentsWithoutClassRoomTest = from w in students
                                           from l in classes
                                           where !l.Students.Contains(w)
                                           select l;

As you can see I can get the answer using optionA, but I would like to understand is it possible to get it done using approach in optionB?

CodePudding user response:

var studentsWithoutClassRoomTest = from w in students
    from l in classes
    where !l.Students.Contains(w)
    select l;

Shouldn't you be selecting w instead of l if you want students?

Use join instead of from and give joining condition using on

CodePudding user response:

Try the following query:

var studentsWithoutClassRoomTest = 
    from w in students
    join s in classes.SelectMany(c => c.Students) on w equals s into gj
    from s in gj.DefaultIfEmpty()
    where s == null
    select w;

CodePudding user response:

I don't think I would say you are "joining" two lists when your goal is to find those who don't belong (more the opposite of joining).

So I would create a HashSet of all Students that are in a ClassRoom and then find the Students not in that set:

var studentsWithClassRooms = (from cr in classRooms
                             from s in cr.Students
                             select s).ToHashSet();
var studentsWithoutClassRoomTest = from s in students
                                   where !studentsWithClassRooms.Contains(s)
                                   select s;

I think joining by Contains would be more like produce a list of Students and the ClassRooms they belong to (assuming a Student could be in more than one ClassRoom):

var studentsAndClassRooms = from s in students
                            from cr in classRooms
                            where cr.Students.Contains(s)
                            group cr by s into crg
                            select new { s = crg.Key, crg };
  • Related