11

CONTEXT

  • I have a list of items (or arbitrary length). I'd like to group them in 'chunks' of a certain size
  • Example: I have 12 customers [0,1,2,3,4,5,6,7,8,9,10,11] and want to group themin chunks of 5 which would give [0,1,2,3,4] [5,6,7,8,9] [10,11]
  • NOTE: In reality I am not working with customers or monotonically increasing integers. I picked that just to simplify asking the question

MY QUESTION

How can I formulate a straightforward LINQ query (using query syntax) that performs this grouping?

BACKGROUND

  • I'm already familiar with how to use LINQ syntax for grouping by a value for example (to group sales by customer id), however I am at a loss how to express the 'chunking' cleanly/elegantly using LINQ. I am not sure if it is even possible in a straightforward way.
  • I can and have already implemented a solution in plain-old-C# without using the LINQ syntax. Thus, my problem is not being blocked on this question, but rather I am looking for ways to express it in LINQ (again cleanly and elegantly)
namenlos
  • 5,111
  • 10
  • 38
  • 38
  • possible duplicate of [Split List into Sublists with LINQ](http://stackoverflow.com/questions/419019/split-list-into-sublists-with-linq) – nawfal Feb 18 '13 at 12:11

4 Answers4

11

You can group them by (index/chunkSize). Example:

    var result =
        from i in array.Select((value, index) => new { Value = value, Index = index })
        group i.Value by i.Index / chunkSize into g
        select g;
okutane
  • 13,754
  • 10
  • 59
  • 67
  • 2
    This is one of those rare cases where a plain for loop and a dictionary is shorter AND more comprehensible than LINQ... – Ray Aug 11 '09 at 11:01
4

For those who prefer the LINQ methods (with lambda expressions), here is Dimitriy Matveev's answer converted:

var result = array
    .Select((value, index) => new { Value = value, Index = index })
    .GroupBy(i => i.Index / chunkSize, v => v.Value);

If you need just an array of value, instead of an IGrouping<T1, T2>, then append the following:

.Select(x => x.ToArray())
Community
  • 1
  • 1
Jesse
  • 8,605
  • 7
  • 47
  • 57
1

Extension method (using Jesse's answer):

public static IEnumerable<T[]> GroupToChunks<T>(this IEnumerable<T> items, int chunkSize)
{
    if (chunkSize <= 0)
    {
        throw new ArgumentException("Chunk size must be positive.", "chunkSize");
    }

    return
        items.Select((item, index) => new { item, index })
             .GroupBy(pair => pair.index / chunkSize, pair => pair.item)
             .Select(grp => grp.ToArray());
}
Community
  • 1
  • 1
frakon
  • 1,948
  • 2
  • 22
  • 26
0

To do the actual grouping, shouldn't it be:

var result = array
.Select((value, index) => new { Value = value, Index = index})
.GroupBy(i => i.Index / chunk, v => v.Value);
  • Steven - you're correct. I've updated my answer. Thanks for catching that. Also, please note that StackOverflow (StackExchange as a whole too) isn't forum style, where you reply to the "above" reply. You posed to answer to the question. I realize you probably didn't have enough rep to add a comment. So, anyway, just trying to help out. – Jesse Oct 26 '16 at 23:02