tags:

views:

70

answers:

3

I have a List of X items. I want to have LINQ query that will convert it into batches (a List of Lists), where each batch has 4 items, except for the last one which can have 1-4 (whatever the remainder is). Also, the number 4 should be configurable so it could 5, 17, etc.

Can anyone tell me how to write that?

List<Item> myItems = ...;
List<List<Item>> myBatches = myItems.????

Thank you in advance!

A: 

Here is a good article about using Take and Skip to do paging, which is identical functionality to what you are requesting. It doesn't get you all of the way to a single line of LINQ, but hopefully helps.

davisoa
+4  A: 

If you're happy with the results being typed as IEnumerable<IEnumerable<T>> then you can do this:

int groupSize = 4;

var myBatches = myItems.Select((x, i) => new { Val = x, Idx = i })
                       .GroupBy(x => x.Idx / groupSize,
                                x => x.Val);

If you want an actual List<List<T>> then you'll need to add a couple of extra ToList calls:

int groupSize = 4;

var myBatches = myItems.Select((x, i) => new { Val = x, Idx = i })
                       .GroupBy(x => x.Idx / groupSize,
                                x => x.Val,
                                (k, g) => g.ToList())
                       .ToList();
LukeH
A: 

This made me think of how we did this before LINQ.

var vessels = new List<Vessel>() 
    { new Vessel() { id =  8, name = "Millennium Falcon" }, 
      new Vessel() { id =  4, name = "Ebon Hawk" },
      new Vessel() { id = 34, name = "Virago"},
      new Vessel() { id = 12, name = "Naboo royal starship"},
      new Vessel() { id = 17, name = "Radiant VII"},
      new Vessel() { id =  7, name = "Lambda-class shuttle"},
      new Vessel() { id = 23, name = "Rogue Shadow"}};

var chunksize=2;

// With LINQ                 
var vesselGroups = vessels.Select((v, i) => new { Vessel = v, Index = i })
                          .GroupBy(c => c.Index / chunksize, c => c.Vessel, (t,e)=>e.ToList())
                          .ToList();

// Before LINQ (most probably not optimal)
var groupedVessels = new List<List<Vessel>>();
var g = new List<Vessel>();
var chunk = chunksize;
foreach(var vessel in vessels)
{
    g.Add(vessel);
    chunk--;
    if (chunk == 0)
    {
        groupedVessels.Add(g);
        g = new List<Vessel>();
        chunk = chunksize;
    }
}
groupedVessels.Add(g);
Jonas Elfström