3

Say I have 23 elements in a list. How can I do foreach taking 5 elements each time and 3 elements the last time? Is there anything like "takeN" method which I can use with foreach or something?

// myList is a list 23 elements
foreach (var x in myList) {
  // x is a list with 5 elements
}
Alan Coromano
  • 24,958
  • 53
  • 135
  • 205

5 Answers5

4

There's nothing in the framework, but you can use MoreLINQ's Batch method:

foreach (var sublist in myList.Batch(5))
{
    // sublist has up to 5 elements
}

(On the final iteration, it will have just 3 elements.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • But using an external library just for one simple extension method? I would rather implement my own `Batch`. – SimpleVar Nov 17 '15 at 16:51
  • @SimpleVar: It takes less time to take the dependency than to implement it *and test it* yourself - and why assume that's the *only* thing you'll want to use from it? – Jon Skeet Nov 17 '15 at 16:51
  • @JonathanCarroll: No, that's not how it works. How it works is in the link to `Batch` in my post, which links to the actual source code. – Jon Skeet Nov 17 '15 at 16:54
  • @JonSkeet Yes, it takes less time. But I'm talking from a POV of someone that has 20minutes to spare. Besides that, I personally think MoreLINQ has some useful extensions, and some other useless extensions, and that I would use it if and when I find the need to - not before that - and not for a single (very easy to implement) helper method. – SimpleVar Nov 17 '15 at 16:54
  • @SimpleVar: Well if you effectively reimplement it yourself, one method at a time, you'll never *need* to... it's not like there's anything in it that can't be reimplemented yourself. But while you claim it's "very easy to implement" there are already other approaches suggested here which haven't been as carefully thought out (e.g. losing laziness). Maybe that's relevant to you, maybe it's not - but by using MoreLINQ you get to use an implementation that someone's thought about a bit longer. If you're not saving time by reimplementing your own method, what *are* you saving? – Jon Skeet Nov 17 '15 at 16:56
  • @JonSkeet I agree it is most helpful. Looking at the source code is helpful as well. I wouldn't reimplement the library on my own if it required a significant amount of work, obviously. I just generally prefer having extra 15 lines of code over having an extra dependency. Still great answer and points OP to solution! – SimpleVar Nov 17 '15 at 16:59
  • 1
    @SimpleVar: I guess it depends on how reliably you think you can implement those 15 lines of code. Given the other solutions provided here, I think the MoreLINQ implementation is a higher quality one... – Jon Skeet Nov 17 '15 at 17:11
  • @JonSkeet Not related to this question, is there something similar in Java? – Some guy Nov 18 '15 at 19:48
  • @Rakesh: In Java 8 there's the `Stream` API instead of LINQ... not sure whether it has batching off the top of my head. – Jon Skeet Nov 18 '15 at 19:57
1

Not tested, but something like this:

        for (int i = 0; i < myList.Count; i += 5)
        {
            var sublist = myList.Skip(i).Take(5);
        }
AD.Net
  • 13,352
  • 2
  • 28
  • 47
0

You can use a regular for loop:

for(int i = 0; i < myList.Count; i += 5) { .. }
Aaron Gates
  • 469
  • 4
  • 15
0

You can do in two steps:

  • Create a pair of value and index
  • Group the values by index/5

The snippet:

var groups = myList.Select((x,i) => new {X=x, I=i/5})
                   .GroupBy(xi => xi.I, xi => xi.X);

Example Program:

using System.Linq;

namespace BatchLinq
{
    class Program
    {
        static void Main(string[] args)
        {

            var myList = Enumerable.Range(0, 23);
            var groups = myList.Select((x,i) => new {X=x, I=i/5})
                       .GroupBy(xi => xi.I, xi => xi.X);

            foreach (var group in groups)
                System.Console.Out.WriteLine("{{ {0} }}", string.Join(", ", group));
        }
    }
}

The output is:

{ 0, 1, 2, 3, 4 }
{ 5, 6, 7, 8, 9 }
{ 10, 11, 12, 13, 14 }
{ 15, 16, 17, 18, 19 }
{ 20, 21, 22 }
fjardon
  • 7,921
  • 22
  • 31
  • Note that by doing that, as soon as you evaluate the very first iteration, it will iterate over the whole of the source sequence. – Jon Skeet Nov 17 '15 at 16:54
0

Edit:

static IEnumerable<IEnumerable<T>> PrepareCollection<T>(List<T> input)
{
    int cnt = 0;

    while (cnt < input.Count)
    {
        IEnumerable<T> arr = input.Skip(cnt).Take(5);
        cnt += 5;
        yield return arr;
    }
}
w.b
  • 11,026
  • 5
  • 30
  • 49