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