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

C#如何单次操作实现TakeWhile效果同时返回匹配序列和剩余序列?

解决方案

现有实现的问题

  • 当前TakeWhile + Skip(a.Count)的写法会至少2次枚举源序列,若源是未物化的IEnumerable<T>(比如流式读取的大集合、数据库查询返回的可枚举对象),会重复执行查询逻辑,性能损耗严重,甚至部分向前只读的枚举器会直接抛出异常。
  • 原业务代码中用Count() > 0判断集合非空会全量遍历序列计数,对大集合来说额外开销极高。

单次遍历实现方案

自定义LINQ扩展方法,单次遍历即可同时返回匹配前缀和剩余序列:

public static class EnumerableExtensions
{
    public static (List<T> Matched, IEnumerable<T> Remaining) SplitTakeWhile<T>(
        this IEnumerable<T> source, 
        Func<T, bool> predicate)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (predicate == null) throw new ArgumentNullException(nameof(predicate));
        
        var matched = new List<T>();
        using var enumerator = source.GetEnumerator();
        
        // 遍历匹配前缀部分
        while (enumerator.MoveNext())
        {
            var current = enumerator.Current;
            if (predicate(current))
            {
                matched.Add(current);
            }
            else
            {
                // 遇到不匹配项,返回已匹配集合 + 剩余序列迭代器
                return (matched, GetRemaining(enumerator));
            }
        }
        
        // 所有元素都满足匹配条件,剩余序列为空
        return (matched, Enumerable.Empty<T>());
    }
    
    // 将枚举器剩余元素转为惰性迭代的IEnumerable
    private static IEnumerable<T> GetRemaining<T>(IEnumerator<T> enumerator)
    {
        do
        {
            yield return enumerator.Current;
        } while (enumerator.MoveNext());
    }
}

优化后的业务代码

while (data.Any())
{
    var firstItem = data.First();
    int y = firstItem.Year;
    var (year, remaining) = data.SplitTakeWhile(c => c.Year == y);
    data = remaining;

    Console.WriteLine($"{year.Count} items in {y}");
}

优化点说明

  • 全程仅枚举1次源序列,无重复遍历开销,适配大集合流式处理场景
  • 用Any()替代Count() > 0判断非空,仅需读取第一个元素即可返回结果,大幅降低大集合下的判断开销
  • 匹配结果直接存储在List中,调用Count属性是O(1)操作,无额外计算成本

内容的提问来源于stack exchange,提问作者Mr. Boy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 03:54:01