1

Possible Duplicate:
LINQ Partition List into Lists of 8 members
how do I chunk an enumerable?

I have a list of many items, and a Method that works well on shorter lists of those same items.

Can I use LINQ to pull off N elements from the big list, and pass them into the Method, N at a time? I'm sure there is an elegant way to to this without having to make an "int i=0;" variable.

Let me be clear, I know that foo.Take(10) will get me 10 items off the list. But I need to keep processing the next set of 10, then the next set of 10 and so on. The pseudo code should be something like:

var shortList = BigList.NiceMethod(10);
foreach (shorty in shortlist)
{
  Method(shorty);
}

This is probably some Group call.

Community
  • 1
  • 1
Daniel Williams
  • 8,912
  • 15
  • 68
  • 107

3 Answers3

3

You can pass an IEnumerable<T> to your method and use Enumerable.Take.

var part = items.Take(10);
method(part);

For the next part you could use Skip+Take:

var part = items.Skip(10).Take(10);
method(part);

Another option: use Enumerable.GroupBy with the remainder operator % to n packets:

int groupCount = 5;
var parts = items.GroupBy(i => i % groupCount);
foreach (var p in parts)
    method(p);

Edit: If you need to partition a sequence into smaller ones with the same size you can use this extension:

public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> collection, int batchSize)
{
    List<T> nextbatch = new List<T>(batchSize);
    foreach (T item in collection)
    {
        nextbatch.Add(item);
        if (nextbatch.Count == batchSize)
        {
            yield return nextbatch;
            nextbatch = new List<T>(batchSize);
        }
    }
    if (nextbatch.Count > 0)
        yield return nextbatch;
}
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
3

This will give you a list of Lists where every List has at most N elements.

int N = 3;
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

var ListOfLists = list.Select((x, inx) => new { Item = x, Group = inx / N })
                        .GroupBy(g => g.Group, g => g.Item)
                        .Select(x => x.ToList())
                        .ToList();

You can also use Morelinq's Batch method

var ListOfLists2 = list.Batch(3).Select(x => x.ToList()).ToList();
L.B
  • 114,136
  • 19
  • 178
  • 224
  • Note the primary difference between this code an `Batch` is that batch is able to defer execution longer. It only eagerly iterates a single batch at a time, not the whole sequence. – Servy Nov 01 '12 at 19:00
  • @Servy of course I know, but sometimes giving answers without materializing the query turns back as "it doesn't work". So I always give answers that way unless It is not explicitly mentioned in question. – L.B Nov 01 '12 at 19:02
0

This works for me

    var l = Enumerable.Range(0, 1000).ToList<int>();
        int size = 11;
        var result = Enumerable.Range(0, l.Count / size + 1)
            .Select(p => l.Skip(p * size).Take(Math.Min(size, l.Count - size * p)).ToList())
            .Where(p=>p.Count > 0).ToList();
Uriil
  • 11,948
  • 11
  • 47
  • 68
  • All good, but requires multiple enumeration of the source. While this not be a problem for a List, if the source enumerable is lazily evaluted, re-enumeration (required for the `.Skip` part of this code) might be costly/undesirable. – spender Nov 01 '12 at 19:13