Monochrome
Monochrome

Reputation: 420

Linq lambda for searching a List within a List, finding a match, then deleting it from the list

I'm trying to learn Linq and I need help with a method that searches a List within a List, finds a match, and deletes it. For example, imagine I have a class called Student:

public class Student
{
   string FirstName;
   string LastName;
}

Then imagine I have another class called Classroom, which has a List<Student>:

public class Classroom
{
   List<Student> Students;
}

And finally, I have one more class, called School, which has a list of Classrooms:

public class School
{
   List<Classroom> Classrooms;
}

Then, I need a method that takes in a Student object, checks to see if the student is in the school, and deletes them if they are. If they're in the school, the method should delete them and return true. If they're not in the school, the method should return false and take no action. Here's an example using foreach loops, which I want to get rid of:

public bool RemoveStudentFromSchool(Student student)
{
   foreach (Classroom c in Classrooms)
   {
      foreach (Student s in c.Students)
      {
         if ((student.FirstName == s.FirstName) && (student.LastName == s.LastName))
         {
            s.Remove(student);

            return true;
         }
      }
   }

   return false;
}

Upvotes: 1

Views: 2943

Answers (2)

Richard Friend
Richard Friend

Reputation: 16018

What about an extension method..

public static bool RemoveFromRoom(this Student student,School school)
{
    if (student == null) throw new ArgumentNullException("student");
    if (school == null) throw new ArgumentNullException("school");
    bool ret = false;
    var room = school.Classrooms.SingleOrDefault(cr=>cr.Students.Contains(student));
    if (room !=null)
    {
        ret = true;
        room.Students.Remove(student);
    }

    return ret;
}

Usage

student.RemoveFromRoom(instanceOfSchool);

Or...

public static bool RemoveStudentFromRoom(this School school,Student student)
{
    if (student == null) throw new ArgumentNullException("student");
    if (school == null) throw new ArgumentNullException("school");
    bool ret = false;
    var room = school.Classrooms.SingleOrDefault(cr=>cr.Students.Contains(student));
    if (room !=null)
    {
        ret = true;
        room.Students.Remove(student);
    }

    return ret;
}

Usage

instanceOfSchool.RemoveStudentFromRoom(student);

Upvotes: 1

ChrisWue
ChrisWue

Reputation: 19020

This assumes a student can only be in one room and Student is IEquatable on first and last name (or the references are equal):

var roomWithStudent = Classrooms.FirstOrDefault(c => c.Students.Any(s => s.Equals(student));
if (roomWithStudent != null)
{
    roomWithStudent.Remove(student);
    return true;
}
return false;

An alternative approach if Student is not IEquatable and the search object passed in is not necessarily the same reference:

var roomWithStudent = Classrooms
                        .SelectMany(c => c.Students.Select(s => new { Room = c, Student = s }))
                        .Where(rs => (student.FirstName == rs.Student.FirstName) && (student.LastName == rs.Student.LastName))
                        .FirstOrDefault();

if (roomWithStudent != null)
{
    roomWithStudent.Room.Students.Remove(roomWithStudent.Student);
    return true;
}
return false;

Upvotes: 3

Related Questions