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 a list to a list of lists, where each sub-list has a given size. The size of each subscription may vary. For instance:

 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 do this quite easily using nested loops, but wondered if there was a tricky way to do this using LINQ?

My initial thought was to use the Aggregate method, but nothing comes to my mind right away.

Thanks.

+4
source share
4 answers

Here is the general IEnumerable function of IEnumerable . You can simply change the return type from IEnumerable<IEnumerable<T>> to IEnumerable<IList<T>> without any changes (since in my implementation it is already a list. To change everything to return a list of lists, you need either call `ToList on result or do more involved refactoring.

Note that technically this does not use LINQ, it just creates a new method that uses the same style and patterns that are 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; } } 
+6
source

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

You can also view sources here .

+5
source

Given the answers of others, I came up with my solution using pure LINQ as follows:

 IList<IList<T>> Batch<T>(IList<T> values, int batchSize) { return values.Aggregate( new List<IList<T>>(), (state, next) => { IList<T> batch = (state.Count > 0) ? state[state.Count - 1] : null; if ((batch == null) || (batch.Count == batchSize)) { batch = new List<T>(batchSize); state.Add(batch); } batch.Add(next); return state; }); } 

This is probably not as efficient as using IEnumerable, but in my circumstances I am dealing with small sets, so it does not matter.

I am going to choose Servy answer as β€œcorrect” because it is independent of the external library and leads me to my decision.

Thank you all for your help :)

0
source
  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); } } 
0
source

All Articles