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 Student
s that are in a ClassRoom
and then find the Student
s 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 Student
s and the ClassRoom
s 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 };