Split List into Sub lists with LINQ C#

To split the C# list into N Sub lists use the next generic helper:

public static class ListExtensions
{
    public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize) 
    {
        return source
            .Select((x, i) => new { Index = i, Value = x })
            .GroupBy(x => x.Index / chunkSize)
            .Select(x => x.Select(v => v.Value).ToList())
            .ToList();
    }
}

Split Example

Here is the list of 7 persons. And I want to split it into chunks in size 2. As a result, we should have 3 chunks with 2 persons and 1 chunk with 1 person. And at the end of the program, I print results grouped by chunks.

The full code example:

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var personList = new List<Person>();
            personList.Add(new Person()
            {
                Id =10,
                FirstName = "Belinda",
                LastName = "Mcintosh"
            });
            personList.Add(new Person()
            {
                Id = 20,
                FirstName = "Cory",
                LastName = "Mcmahon"
            });
            personList.Add(new Person()
            {
                Id = 30,
                FirstName = "Joe",
                LastName = "Horton"
            });
            personList.Add(new Person()
            {
                Id = 40,
                FirstName = "Virginia",
                LastName = "Rice"
            });
            personList.Add(new Person()
            {
                Id = 50,
                FirstName = "Kody",
                LastName = "Taylor"
            });
            personList.Add(new Person()
            {
                Id = 60,
                FirstName = "Gordon",
                LastName = "Mercer"
            });
            personList.Add(new Person()
            {
                Id = 70,
                FirstName = "Carolina",
                LastName = "Mcintosh"
            });
            const int chunkSize = 2;
            var chunks = personList.ChunkBy<Person>(chunkSize);
            int i=0;
            foreach(var c in chunks)
            {
                i++;
                Console.WriteLine($"Chucnk #{i}");
                foreach(var person in c)
                {
                    Console.WriteLine($"{person.FirstName} {person.LastName}");
                }
                Console.WriteLine(Environment.NewLine);
            }
        }
    }
    public class Person 
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    public static class ListExtensions
    {
        public static List<List<T>> ChunkBy<T>(this List<T> source, int chunkSize)
        {
            return source
                .Select((x, i) => new { Index = i, Value = x })
                .GroupBy(x => x.Index / chunkSize)
                .Select(x => x.Select(v => v.Value).ToList())
                .ToList();
        }
    }
}

Print Result(sorry for typo):

How Does it Work?

Let’s debug each line and see what intermediate results we have on lambda expressions. To simplify our example I rewrote it in a shorter manner without a generic function:
explore lambda lines split list
Output:
view lambda expression in output window
The ‘tmp1‘ variable contains the list of anonymous objects: {Index, Value(aka Person)}.
The ‘tmp2‘ contains GroupedEnumerable. To understand how Group calculates I prepared a ‘debug‘ table:

IndexChunk SizeGroup(integer division Index/ChunkSize)
020
120
221
321
422
522
623
And ‘tmp3’ contains a list of chunked lists.

How to Split List into Sub List if you use .net 6 and C# 10

If you use C# 10 you can find a new function Chunk. Look at my article about LINQ improvement in .NET 6 where I describe how the above code could be replaced by the Chunk function.

You may also be interested in reading:

Leave a Reply

Your email address will not be published. Required fields are marked *