Derik Whittaker

Syndication

News


How to split a list into ‘chunks’ (Fun Code)

Today I had yet another need that I never recall having in the past.  I needed to take an list/array of items and split it into chunks, effectively creating a multiple dimensional list.

For Example, if I had the list of items below, I wanted to split it into chunks of 2 items each.

var items = new List<string>{ "A", "B", "C", "D", "E", "F", "G", "H", "I" };

I expect the result to be as seen below (this is from LINQPad)
image

 

How to do this?  Actually it is quite easy.  The code below will do this for you.

public static IList<IList<T>> SplitIntoChunks<t>(this IList toSplit, int chunkSize)
{
	var results = new List<IList<T>>();
	var totalItemsCount = toSplit.Count();

	var chunksRequired = (int)Math.Ceiling((decimal)totalItemsCount / (decimal)chunkSize);
	
	for (int i = 0; i < chunksRequired; i++)
	{
		var chunksTaken = toSplit.Skip(chunkSize * i).Take(chunkSize).ToList();		
		results.Add(chunksTaken);	
	}
	
	return results;
}

Now I am sure there are much better ways to do this, but hey this just works.

Till next time,


Posted 10-20-2012 5:33 AM by Derik Whittaker
Filed under: ,

[Advertisement]

Comments

styx31 wrote re: How to split a list into ‘chunks’ (Fun Code)
on 10-20-2012 6:43 AM

I've used another code before, based on Select(Func<TElement, int>) :

return toSplit.Select((x, i) => new { Index = i, Value = x}).GroupBy(x => x.Index / chunkSize).Select(x => x.Select(v => v.Value).ToList()).ToList();

Steve Ruble wrote re: How to split a list into ‘chunks’ (Fun Code)
on 10-20-2012 2:16 PM

Thanks, this is a neat kata! I'm finding it really difficult to implement it nicely in LINQ; using GroupBy is not very performant, and when I used Aggregate it was not very readable (actually, to my eye the GroupBy version doesn't make the purpose of the code very obvious either).

The most concise O(n) version I could think of was a method like

public IList<IList<T>> Chunk<T>(this IEnumerable<T> source, int chunkSize)

{

var accumulator = new List<T>(chunkSize);

var list = new List<List<T>>(){accumulator};

foreach (var element in source)

{

accumulator.Add(element);

if(accumulator.Count == chunkSize)

list.Add(accumulator = new List<T>(chunkSize));

}

return list;

}

Josh wrote re: How to split a list into ‘chunks’ (Fun Code)
on 10-21-2012 3:21 AM

For a lazy evaluated and IEnumerable version of the same, the following should work: (gist.github.com/3926224)

static class GroupingExtensions

{

public static IEnumerable<IEnumerable<T>> GroupByCount<T>(this IEnumerable<T> source, int count)

{

if (source == null) throw new ArgumentNullException("source");

return GroupByCountIterator<T>(source, count);

}

static IEnumerable<IEnumerable<T>> GroupByCountIterator<T> (IEnumerable<T> source, int count)

{

using (IEnumerator<T> e = source.GetEnumerator())

{

while (e.MoveNext())

{

yield return TakeIterator<T>(e, count);

}

}

}

static IEnumerable<T> TakeIterator<T>(IEnumerator<T> e, int count)

{

if (count <= 0)

return;

do

{

yield return e.Current;

} while (--count > 0 && e.MoveNext());

}

}

... wrote re: How to split a list into ‘chunks’ (Fun Code)
on 10-21-2012 10:19 PM

"foobar".Reverse() and StackOverflow.Users.OrderbyDescending(u => u.Reputation).First() have an excellent 'morelinq' project

code.google.com/.../OperatorsOverview

While this functionality is covered in their Batch method, there are tons of useful things in there.

mg wrote re: How to split a list into ‘chunks’ (Fun Code)
on 10-22-2012 7:32 AM

Using recursion (changed IList to IEnumerable for brevity:

public IEnumerable<IEnumerable<T>> Split<T>(

IEnumerable<T> items, int maxSize)

{

if (items.Count() <= maxSize)

return new [] {items};

else return (new[] {items.Take(maxSize)})

.Concat(Split(items.Skip(maxSize), maxSize));

}

mg wrote re: How to split a list into ‘chunks’ (Fun Code)
on 10-22-2012 7:36 AM

Or tail recursion (back to ILists):

public IList<IList<T>> Split2<T>(

IList<T> items, int maxSize)

{

var results = new List<IList<T>>();

SplitRecursive(results, items, maxSize);

return results;

}

private void SplitRecursive<T>(

IList<IList<T>> results,

IList<T> items, int maxSize)

{

if (items.Count() <= maxSize)

{

results.Add(new List<T>(items));

return;

}

results.Add(new List<T>(items.Take(maxSize)));

SplitRecursive(results,

items.Skip(maxSize).ToList(), maxSize);

}

Eric Gunn wrote re: How to split a list into ‘chunks’ (Fun Code)
on 10-22-2012 9:30 AM

using recursive lambda

public static IEnumerable<IEnumerable<T>> SplitIntoChunks<T>(this IEnumerable<T> toSplit, int chunkSize)  

{

Func<IEnumerable<T>,  IEnumerable<IEnumerable<T>>> chunk = (src) => null;

chunk = (src) =>  src.Take(chunkSize).Count ( ) < chunkSize

? new T[][] {src.ToArray()}

: (new T[][] {src.Take(chunkSize).ToArray()}).Union(chunk(src.Skip(chunkSize)));

return chunk(toSplit);

James Curran wrote re: How to split a list into ‘chunks’ (Fun Code)
on 10-23-2012 5:19 PM

If you're will to require a list instead of an IList as input:

public static IList<IList<T>> SplitIntoChunks<T>(List<T> toSplit, int chunkSize)  

{

var results = new List<IList<T>>();  

for(int i=0; i<toSplit.Count; i+= chunkSize)

{

results.Add(toSplit.GetRange(i, Math.Min(chunkSize,toSplit.Count - i )));

}

return results;

}

(Can be made short if you'd allow a IEnumerator<ILIst<T>> as the return type.

Mike Minutillo wrote re: How to split a list into ‘chunks’ (Fun Code)
on 11-05-2012 3:42 AM

The terse but awesome double yield while-do-while version gist.github.com/4016067 which is essentially the same version as Josh's now that I look.

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)