Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# - Splitting a list into n amount of sub-lists

Tags:

c#

linq

I would like to split a list into 'n' amount of sub-lists.

I have a list of Form teachers and a list of Students. Every Student is assigned to one Form teacher and each Form teacher can have more than one Student. The list of Form teachers is dynamic - it is being populated based on checkbox selection on the form (i.e: there may be one, three, six, etc. in the list).

//A method to assign the Selected Form teachers to the Students
private void AssignFormTeachers(List<FormTeacher> formTeacherList, List<Student> studentList)
{
    int numFormTeachers = formTeacherList.Count;

    //Sort the Students by Course - this ensures cohort identity.
    studentList = studentList.OrderBy(Student => Student.CourseID).ToList();

    //Split the list according to the number of Form teachers
    List<List<Student>> splitStudentList = splitList(numFormTeachers , studentList);

The splitList() method is where I'm attempting to split the list into a list of Student lists, but I'm having a problem. Let's say there are 3 Form teachers - I can't seem to split the list into 3 sub-lists, but rather end up with lists of 3 Students.

I would really appreciate some help with this. I have searched for a possible solution, but every time I end up with lists of size 'n', rather than 'n' amount of lists. If this question has been answered before, please point me in the direction of that answer.

like image 992
normgatt Avatar asked Dec 02 '22 20:12

normgatt


1 Answers

You're trying to partition your list into n parts with equal number of elements?

Try GroupBy:

var splitStudentList = studentList.Select((s, i) => new { s, i })
                                  .GroupBy(x => x.i % numFormTeachers)
                                  .Select(g => g.Select(x => x.s).ToList())
                                  .ToList();

Or you can create your own extension method to do that. I've described how to do it right on my blog: Partitioning the collection using LINQ: different approaches, different performance, the same result.

public IEnumerable<IEnumerable<T>> Partition<T>(IEnumerable<T> source, int size)
{
    var partition = new List<T>(size);
    var counter = 0;

    using (var enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            partition.Add(enumerator.Current);
            counter++;
            if (counter % size == 0)
            {
                yield return partition.ToList();
                partition.Clear();
                counter = 0;
            }
        }

        if (counter != 0)
            yield return partition;
    }
}

usage:

var splitStudentList = studentList.Partition(numFormTeachers)
                                  .Select(x => x.ToList())
                                  .ToList();
like image 61
MarcinJuraszek Avatar answered Dec 05 '22 09:12

MarcinJuraszek