dana dana - 3 months ago 12
C# Question

Use LINQ to Convert a List to a List of Lists

I have a list of values:

IList<V> values = { V1, V2, V3, V4, V5, V6, V7 };


I would like to convert the list into a list of lists, where each sub-list is a specified size. The size of each sub-list could vary. For example:

IList<IList<V>> values_size2 = { { V1, V2 }, { V3, V4 }, { V5, V6 }, { V7 } };
IList<IList<V>> values_size3 = { { V1, V2, V3 }, { V4, V5, V6 }, { V7 } };
IList<IList<V>> values_size4 = { { V1, V2, V3, V4 }, { V5, V6, V7 } };


I could probably do this pretty easily using nested loops, but was wondering if there was a clever way to do this using LINQ?

My initial thought would be to use the Aggregate method somehow, but nothing comes to mind right away.

Thanks.

Answer

Here is a generic IEnumerable based Batch function. You can just change the return type from IEnumerable<IEnumerable<T>> to IEnumerable<IList<T>> with no other changes (since in my implementation it's already a list. To change the whole thing to return a list of lists you'd need to either call `ToList on the result, or make a more involved refactor.

Note that technically this isn't using LINQ, it's just creating a new method that uses the same style and patterns commonly used by LINQ.

public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source
    , int batchSize)
{
    //TODO validate parameters

    List<T> buffer = new List<T>();

    foreach (T item in source)
    {
        buffer.Add(item);

        if (buffer.Count >= batchSize)
        {
            yield return buffer;
            buffer = new List<T>();
        }
    }
    if (buffer.Count >= 0)
    {
        yield return buffer;
    }
}
Comments