[英]How do I segment the elements iterated over in a foreach loop
I need to loop through an entire list of users, but need to grab 20 at a time. 我需要循环遍历整个用户列表,但需要一次抓取20个。
foreach (var student in Class.Students.Take(20))
{
Console.WriteLine("You belong to Group " + groupNumber);
groupNumber++;
}
This way the first 20 will belong to Group 1, the second 20 to Group 2, and so on. 这样,前20个将属于组1,第二个20属于组2,依此类推。
Is Take the correct syntax for this? 采取正确的语法吗? I believe Take will take 20 then be done.
我相信Take将花费20来完成。 Thanks!
谢谢!
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());
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;
}
}
Note that the last chunk may be smaller than the specified chunk size. 请注意,最后一个块可能小于指定的块大小。
EDIT The first version used Skip()/Take()
, but as Chris pointed out, GetRange
is considerably faster. 编辑第一个版本使用
Skip()/Take()
,但正如克里斯指出的那样, GetRange
要快得多。
You could project the group number onto each item in the original list using Select
and an anonymous type like this: 您可以使用
Select
和匿名类型将组编号投影到原始列表中的每个项目上,如下所示:
var assigned = Class.Students.Select(
(item, index) => new
{
Student = item,
GroupNumber = index / 20 + 1
});
Then you can use it like this: 然后你可以像这样使用它:
foreach (var item in assigned)
{
Console.WriteLine("Student = " + item.Student.Name);
Console.WriteLine("You belong to Group " + item.GroupNumber.ToString());
}
Or if you wanted to pick off a particular group. 或者,如果你想挑选一个特定的群体。
foreach (var student in assigned.Where(x => x.GroupNumber == 5))
{
Console.WriteLine("Name = " + student.Name);
}
Or if you wanted to actually group them to perform 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 lump the items in batches and you do not care about having the batch number information 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 could 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);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.