I have a list of strings which I send to a queue. I need to split up the list so that I end up with a list of lists where each list contains a maximum (user defined) number of strings. So for example, if I have a list with the following A,B,C,D,E,F,G,H,I and the max size of a list is 4, I want to end up with a list of lists where the first list item contains: A,B,C,D, the second list has: E,F,G,H and the last list item just contains: I. I have looked at the “TakeWhile” function but am not sure if this is the best approach. Any solution for this?
Asked
Active
Viewed 3.7k times
3 Answers
21
You can set up a List<IEnumerable<string>>
and then use Skip
and Take
to split the list:
IEnumerable<string> allStrings = new[] { "A", "B", "C", "D", "E", "F", "G", "H", "I" };
List<IEnumerable<string>> listOfLists = new List<IEnumerable<string>>();
for (int i = 0; i < allStrings.Count(); i += 4)
{
listOfLists.Add(allStrings.Skip(i).Take(4));
}
Now listOfLists
will contain, well, a list of lists.

Fredrik Mörk
- 155,851
- 29
- 291
- 343
-
I voted for this as it's just what I needed. RPM1984 also gave a good answer but this one fitted straight into my code. – Retrocoder Nov 05 '10 at 11:00
-
what if i need to split list to 5 lists no matter how many strings those lists would end up ? – Skuta Dec 20 '12 at 16:39
21
/// <summary>
/// Splits a <see cref="List{T}"/> into multiple chunks.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">The list to be chunked.</param>
/// <param name="chunkSize">The size of each chunk.</param>
/// <returns>A list of chunks.</returns>
public static List<List<T>> SplitIntoChunks<T>(List<T> list, int chunkSize)
{
if (chunkSize <= 0)
{
throw new ArgumentException("chunkSize must be greater than 0.");
}
List<List<T>> retVal = new List<List<T>>();
int index = 0;
while (index < list.Count)
{
int count = list.Count - index > chunkSize ? chunkSize : list.Count - index;
retVal.Add(list.GetRange(index, count));
index += chunkSize;
}
return retVal;
}
Reference: http://www.chinhdo.com/20080515/chunking/

RPM1984
- 72,246
- 58
- 225
- 350
4
Some related reading:
- Split a collection into `n` parts with LINQ?
- Split List into Sublists with LINQ
- LINQ Partition List into Lists of 8 members
Otherwise, minor variation on accepted answer to work with enumerables (for lazy-loading and processing, in case the list is big/expensive). I would note that materializing each chunk/segment (e.g. via .ToList
or .ToArray
, or simply enumerating each chunk) could have sideeffects -- see tests.
Methods
// so you're not repeatedly counting an enumerable
IEnumerable<IEnumerable<T>> Chunk<T>(IEnumerable<T> list, int totalSize, int chunkSize) {
int i = 0;
while(i < totalSize) {
yield return list.Skip(i).Take(chunkSize);
i += chunkSize;
}
}
// convenience for "countable" lists
IEnumerable<IEnumerable<T>> Chunk<T>(ICollection<T> list, int chunkSize) {
return Chunk(list, list.Count, chunkSize);
}
IEnumerable<IEnumerable<T>> Chunk<T>(IEnumerable<T> list, int chunkSize) {
return Chunk(list, list.Count(), chunkSize);
}
Test (Linqpad)
(note: I had to include the Assert
methods for linqpad)
void Main()
{
var length = 10;
var size = 4;
test(10, 4);
test(10, 6);
test(10, 2);
test(10, 1);
var sideeffects = Enumerable.Range(1, 10).Select(i => {
string.Format("Side effect on {0}", i).Dump();
return i;
});
"--------------".Dump("Before Chunking");
var result = Chunk(sideeffects, 4);
"--------------".Dump("After Chunking");
result.Dump("SideEffects");
var list = new List<int>();
foreach(var segment in result) {
list.AddRange(segment);
}
list.Dump("After crawling");
var segment3 = result.Last().ToList();
segment3.Dump("Last Segment");
}
// test
void test(int length, int size) {
var list = Enumerable.Range(1, length);
var c1 = Chunk(list, size);
c1.Dump(string.Format("Results for [{0} into {1}]", length, size));
Assert.AreEqual( (int) Math.Ceiling( (double)length / (double)size), c1.Count(), "Unexpected number of chunks");
Assert.IsTrue(c1.All(c => c.Count() <= size), "Unexpected size of chunks");
}
-
The best solution I've found is from MoreLinq -- https://code.google.com/p/morelinq/source/browse/MoreLinq/Batch.cs – drzaus Nov 04 '15 at 16:15