如何在foreach循环中对迭代的元素进行分段

我需要遍历整个用户列表,但需要一次抓取20个。

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

这样,前20个将属于组1,第二个20属于组2,依此类推。

采取正确的语法吗? 我相信Take将花费20来完成。 谢谢!

你可以这样做:

 int i = 0; foreach (var grouping in Class.Students.GroupBy(s => ++i / 20)) Console.WriteLine("You belong to Group " + grouping.Key.ToString()); 

对于类似的问题,我曾经做过一个扩展方法:

 public static IEnumerable> ToChunks(this IEnumerable 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; } } 

请注意,最后一个块可能小于指定的块大小。

编辑第一个版本使用了Skip()/Take() ,但正如克里斯指出的那样, GetRange要快得多。

您可以使用Select和匿名类型将组号投影到原始列表中的每个项目上,如下所示:

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

然后你可以像这样使用它:

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

或者,如果你想挑选一个特定的群体。

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

或者,如果您想实际将它们分组以执行聚合

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

现在,如果您只想批量生产物品并且不关心批次编号信息,则可以创建这种简单的扩展方法。

 public static IEnumerable> Batch(this IEnumerable 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); } } 

你可以像这样使用你的新扩展方法。

 foreach (var batch in Class.Students.Batch(20)) { foreach (var student in batch) { Console.WriteLine("Student = " + student.Name); } }