1

I have a collection of car objects and i am looking through them like this:

 var slide = CreateSlide();
 foreach (var car in carCollection) {
      displayonSlide(car, slide)
 }

I now realize that i can only fit 5 cars on a slide so i need to take the carCollection and break it up into collections of 5 and then do the loop through each of those 5 (so i create a new slide for each 5 cars that exist in the collection.

What is the best way to break up a single collection into a number of smaller collection based on bucketing by a certain number of items (5 in this case)

obviously the last collection might have the remainder if not divisible.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
leora
  • 188,729
  • 360
  • 878
  • 1,366
  • 1
    @ByteBlast - can you elaborate a bit on how you would use take to create different collectison – leora Aug 13 '13 at 03:10
  • Initially I thought that using a combination of `Take` and `Skip` would be the best solution but I have since changed my mind :-p – User 12345678 Aug 13 '13 at 03:43
  • Similar to http://stackoverflow.com/questions/419019/split-list-into-sublists-with-linq The answers there go into detail about the performance/memory tradeoff with different implementations. – Cameron MacFarland Aug 13 '13 at 03:53

4 Answers4

3

I use this extension method for my code

public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> t, int size)
{
   while (t.Any())
   {
      yield return t.Take(size);
      t = t.Skip(size);
   }
}
Konstantin
  • 3,254
  • 15
  • 20
0

Using LINQ:

    var slides = carCollection
        .Select((car, index) => new { car, index })
        .GroupBy(c => c.index / 5)
        .Select( g=>
        {
            var slide = CreateSlide();
            g.ToList().ForEach(c => displayonSlide(c.car, slide));
            return slide;
        }).ToList();
fcuesta
  • 4,429
  • 1
  • 18
  • 13
0

If your collection is List, you can use GetRange() method:

var input = new List<int> { 1, 5, 6, 7, 8, 9, 34, 14 };
var k = 5

var res = Enumerable.Range(0, (input.Count - 1) / k + 1)
                    .Select(i => input.GetRange(i * k, Math.Min(k, input.Count - i * k)))
                    .ToList();
Roman Pekar
  • 107,110
  • 28
  • 195
  • 197
0

To avoid grouping and maths,

IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> source, int size)
{
    var partition = new T[size];
    var count = 0;

    foreach(var t in source)
    {
        partition[count] = t;
        count ++;

        if (count == size)
        {
            yield return partition;
            var partition = new T[size];
            var count = 0;
        }
    }

    if (count > 0)
    {
        return partition.Take(count);
    }
}

so you could do

cars.Partition(5).AsParallel().ForAll(pageSet =>
{
    var slide = CreateSlide();
    foreach(var car in pageSet)
    {
        DisplayOnSlide(car, slide);
    }
});
Jodrell
  • 34,946
  • 5
  • 87
  • 124