How to segment elements recycled in foreach loop

I need to scroll through the entire list of users, but you need to grab 20 at a time.

foreach (var student in Class.Students.Take(20)) { Console.WriteLine("You belong to Group " + groupNumber); groupNumber++; } 

Thus, the first 20 will belong to group 1, the second 20 to group 2, etc.

Take the correct syntax for this? I believe Take will take 20 years. Thank!

+9
c # foreach linq
Jul 27 '11 at 18:27
source share
3 answers

You can do something like this:

 int i = 0; foreach (var grouping in Class.Students.GroupBy(s => ++i / 20)) Console.WriteLine("You belong to Group " + grouping.Key.ToString()); 
+13
Jul 27 '11 at 18:31
source share

For a similar problem, I once made an extension method:

 public static IEnumerable<IEnumerable<T>> ToChunks<T>(this IEnumerable<T> enumerable, int chunkSize) { int itemsReturned = 0; var list = enumerable.ToList(); // Prevent multiple execution of IEnumerable. int count = list.Count; while (itemsReturned < count) { int currentChunkSize = Math.Min(chunkSize, count - itemsReturned); yield return list.GetRange(itemsReturned, currentChunkSize); itemsReturned += currentChunkSize; } } 

Please note that the last fragment may be smaller than the specified block size.

EDIT The first version used Skip()/Take() , but, as Chris noted, GetRange much faster.

+9
Jul 27 2018-11-23T00:
source share

You can project the group number on each item in the source list using Select and an anonymous type, for example:

 var assigned = Class.Students.Select( (item, index) => new { Student = item, GroupNumber = index / 20 + 1 }); 

Then you can use it as follows:

 foreach (var item in assigned) { Console.WriteLine("Student = " + item.Student.Name); Console.WriteLine("You belong to Group " + item.GroupNumber.ToString()); } 

Or if you want to select a specific group.

 foreach (var student in assigned.Where(x => x.GroupNumber == 5)) { Console.WriteLine("Name = " + student.Name); } 

Or, if you want to actually group them to execute aggregates

 foreach (var group in assigned.GroupBy(x => x.GroupNumber)) { Console.WriteLine("Average age = " + group.Select(x => x.Student.Age).Average().ToString()); } 

Now, if you just want to combine the elements in packages and you do not need to have information about the batch number, you can create this simple extension method.

 public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> target, int size) { var assigned = target.Select( (item, index) => new { Value = item, BatchNumber = index / size }); foreach (var group in assigned.GroupBy(x => x.BatchNumber)) { yield return group.Select(x => x.Value); } } 

And you can use your new extension method like this.

 foreach (var batch in Class.Students.Batch(20)) { foreach (var student in batch) { Console.WriteLine("Student = " + student.Name); } } 
0
Jul 27 '11 at 20:29
source share



All Articles