You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#用yield实现List分块 如何调整使末尾分块大小更均匀

问题说明

使用yield return实现集合分块时,指定单块最大长度chunkSize=4,待拆分列表共18个元素,原有分块逻辑输出的块长度为4、4、4、4、2,需要调整逻辑得到更均匀的分块结果4、4、4、3、3,且单块长度不超过指定的chunkSize。

原有测试代码:

List<string> testList = new List<string>
{
  "1","2","3","4","5","6","7","8","9",
  "10","11","12","13","14","15","16","17","18"
};
// 原代码此处缺少分号,且泛型参数与列表类型不匹配,属于笔误
int chunkSize = 4;
IEnumerable<IEnumerable<string>> chunkList = ChunkBy(testList, chunkSize);  

原有分块实现:

private static IEnumerable<IEnumerable<TSource>> ChunkBy<TSource>(IEnumerable<TSource> source, int chunkSize)
{
    while (source.Any())
    {
        yield return source.Take(chunkSize);
        source = source.Skip(chunkSize);
    }
}

注:原有实现存在性能隐患:每次调用Any()、Take()、Skip()都会重新遍历源序列,如果传入的是延迟执行的迭代器/数据库查询,会产生重复查询、结果不一致的问题。

调整方案

完全可以实现均匀分块,核心逻辑为:

  • 先将源序列单次遍历转为内存集合,避免重复遍历开销
  • 根据总元素数、指定的单块最大长度,计算实际需要的总块数
  • 计算基础块长度,以及需要多分配1个元素的块数量,保证所有块的长度差不超过1,且最大块长度不超过指定的chunkSize

调整后的实现代码:

private static IEnumerable<IEnumerable<TSource>> ChunkBy<TSource>(IEnumerable<TSource> source, int chunkSize)
{
    // 参数校验
    if (source == null)
        throw new ArgumentNullException(nameof(source));
    if (chunkSize < 1)
        throw new ArgumentOutOfRangeException(nameof(chunkSize), "分块大小必须大于0");
    
    // 单次遍历转为内存集合,避免重复遍历
    var sourceList = source.ToList();
    int totalCount = sourceList.Count;
    if (totalCount == 0)
        yield break;
    
    // 计算总块数:保证单块最大长度不超过chunkSize
    int chunkCount = (int)Math.Ceiling(totalCount / (double)chunkSize);
    // 计算基础块长度、需要多分配1个元素的块数
    int baseChunkSize = totalCount / chunkCount;
    int remainder = totalCount % chunkCount;
    
    int currentIndex = 0;
    for (int i = 0; i < chunkCount; i++)
    {
        // 前remainder个块,每个块多分配1个元素
        int currentChunkSize = baseChunkSize + (i < remainder ? 1 : 0);
        yield return sourceList.GetRange(currentIndex, currentChunkSize);
        currentIndex += currentChunkSize;
    }
}

逻辑验证

以18个元素、chunkSize=4的场景计算:

  • 总块数 = Ceiling(18/4) = 5
  • 基础块长度 = 18 / 5 = 3
  • 余数值 = 18 % 5 = 3
  • 前3个块长度为3+1=4,后2个块长度为3,最终分块结果为4、4、4、3、3,符合预期。

该实现同时兼容其他场景,例如10个元素、chunkSize=3时,分块结果为3、3、2、2,不会出现最后一块仅1个元素的不均匀情况。


内容的提问来源于stack exchange,提问作者Nejox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 18:18:51