dana
dana

Reputation: 18105

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.

Upvotes: 4

Views: 2255

Answers (4)

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236188

You can use MoreLINQ Batch extension (available from Nuget):

IList<IList<V>> values_size2 = values.Batch(2);
IList<IList<V>> values_size3 = values.Batch(3);
IList<IList<V>> values_size4 = values.Batch(4);

Also you can view sources here.

Upvotes: 5

Magnetron
Magnetron

Reputation: 8543

With .NET 6 you can use the new Chunk Linq method

List<IList<V>> values_size2 = values.Chunk(2).ToList();
List<IList<V>> values_size3 = values.Chunk(3).ToList();
List<IList<V>> values_size4 = values.Chunk(4).ToList();

Upvotes: 1

lapsick
lapsick

Reputation: 53

 public static IEnumerable<IEnumerable<T>> Chunks<T>(this IEnumerable<T> source, int chunkSize)
 {
     while (source.Any())
     {
         yield return source.Take(chunkSize);
         source = source.Skip(chunkSize);
     }
 }

Upvotes: 1

Servy
Servy

Reputation: 203804

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;
    }
}

Upvotes: 6

Related Questions