Reputation: 18105
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
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
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
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
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