2

I have a model with list items:

public class Student{
    public int StudentId { get; set; }
    public int ClassId { get; set; }
}

The table values are similar to the following:

StudentId ClassId
1 8
2 6
1 3
3 8
2 3
3 2
4 8
1 6
3 6
2 2

classId list for filter:

ClassId
8
6

I want to select the list of StudentId where are in all filter classId.

StudentId
1
3

I use this code but not working:

List<int> lstStudentId = Students.GroupBy(o => o.StudentId).Where(o => o.All(m => filterClassId.All(s => s == m.ClassId ))).Select(o => o.Key).ToList();
jps
  • 20,041
  • 15
  • 75
  • 79
misha co
  • 23
  • 4

2 Answers2

2

You write :

List<int> lstStudentId = Students
    .GroupBy(o => o.StudentId)
    .Where(o => o.All(m => filterClassId.All(s => s == m.ClassId)))
    .Select(o => o.Key).ToList();

The Where check all student's classes are in the filter... but you want the inverse, all filtered classes are in the student.

Just reverse the condition :

var lstStudentId = Students
    .GroupBy(o => o.StudentId)
    .Where(g => filterClassId.All(f => g.Any(s => s.ClassId == f)))
    .Select(g => g.Key)
    .ToList();

A alternative, it's to check if the filter less the student's class result in nothing. Then the student has all class in the filter :

var lstStudentId = Students
    .GroupBy(o => o.StudentId)
    .Where(g => !filterClassId.Except(g.Select(s => s.ClassId)).Any())
    .Select(g => g.Key)
    .ToList();
vernou
  • 6,818
  • 5
  • 30
  • 58
0

You can use Intersect, first implemet IEqualityComparer for the Student model:

class StudentComparer : IEqualityComparer<Student>
{
    public bool Equals(Student? x, Student? y) => x.StudenId == y.StudenId;
    public int GetHashCode([DisallowNull] Student obj) => obj.StudenId.GetHashCode();
}

Then you are able to use Intersect as follows:

var commonStudents = students.Where(x => x.ClassId == 8)
    .Intersect(students.Where(x => x.ClassId == 6), new StudentComparer())
    .Select(x => new { x.StudenId }).ToList();
mshwf
  • 7,009
  • 12
  • 59
  • 133