C# 如何分割foreach循环中迭代的元素
我需要循环浏览整个用户列表,但每次需要抓取20个C# 如何分割foreach循环中迭代的元素,c#,linq,foreach,C#,Linq,Foreach,我需要循环浏览整个用户列表,但每次需要抓取20个 foreach (var student in Class.Students.Take(20)) { Console.WriteLine("You belong to Group " + groupNumber); groupNumber++; } 这样,前20个属于组1,后20个属于组2,依此类推 是否对此使用正确的语法?我相信需要20分钟才能完成。谢谢 您可以这样做: int i = 0; foreach (var groupi
foreach (var student in Class.Students.Take(20))
{
Console.WriteLine("You belong to Group " + groupNumber);
groupNumber++;
}
这样,前20个属于组1,后20个属于组2,依此类推
是否对此使用正确的语法?我相信需要20分钟才能完成。谢谢 您可以这样做:
int i = 0;
foreach (var grouping in Class.Students.GroupBy(s => ++i / 20))
Console.WriteLine("You belong to Group " + grouping.Key.ToString());
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());
}
您可以使用
Select
和以下匿名类型将组号投影到原始列表中的每个项目上:
int i = 0;
foreach (var grouping in Class.Students.GroupBy(s => ++i / 20))
Console.WriteLine("You belong to Group " + grouping.Key.ToString());
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());
}
然后你可以这样使用它:
int i = 0;
foreach (var grouping in Class.Students.GroupBy(s => ++i / 20))
Console.WriteLine("You belong to Group " + grouping.Key.ToString());
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<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);
}
}
对于类似的问题,我曾经提出了一种扩展方法:
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;
}
}
公共静态IEnumerable ToChunks(此IEnumerable可枚举,int chunkSize)
{
int itemsreturn=0;
var list=enumerable.ToList();//防止多次执行IEnumerable。
int count=list.count;
while(itemsreturn
请注意,最后一个块可能小于指定的块大小
编辑
第一个版本使用了
Skip()/Take()
,但正如Chris指出的那样,GetRange
要快得多。谢谢MikeP!这很有帮助。如果我需要给一组中的每个学生分配一个特定的值,我会怎么做?我觉得我必须在某个时候对每个对象进行嵌套。分组对象对于分组到其中的元素也是可枚举的。因此,只需一个foreach(分组中的var student)就可以做到这一点。这段代码不是因为预增量而有一个off by one错误吗?本质上,您是从i=1
开始迭代,而不是从0开始。例如,如果组大小为2,则可枚举的第一个元素将单独位于第一个分组中,因为(0+1)/2==0
,但(1+1)/2==1
。您犯了与许多其他海报相同的错误,这些海报后来删除了他们的回复。你不能连续拿20件物品;前二十名学生中的每一位都将属于不同的小组!此外,您实际上也没有对任何内容进行分组。如果你想在一个小组里迭代学生,你的方法会让你感到非常枯燥。@MikeP:是的,很好。固定的。我还将grouped
重命名为assigned
,以更好地反映实际发生的情况。如果OP真的想迭代某个特定组的学生,你可以做assigned.Where(x=>x.GroupNumber==value)
或assigned.GroupBy(x=>x.GroupNumber)
,尽管根据我在问题中看到的情况,这看起来没有必要。我想LINQ的一个有趣的方面是,有很多方法可以做同样的事情。无论如何,是的,我完全被%
而不是/
的东西噎住了。GetRange比Skip/TakeHey快4000多倍,谢谢@ChrisGessler。发现自己忽视了一种“好的旧的”方法的存在是令人尴尬的,这种方法做得更好(而我总是对自己说linq不是一切的答案)。在一个包含大量非原始对象的基准测试中,我发现GetRange比Skip()/Take()
提高了10+以上。很好的回答。@GertArnold这是一个非常古老的答案,但您能否提供一个异步版本作为对我问题的回答: