linq Custom Inclusive TakeWhile(),有更好的方法吗?

pbwdgjma  于 2023-03-27  发布在  其他
关注(0)|答案(3)|浏览(156)

我编写了一个自定义LINQ扩展方法,它将TakeWhile()方法扩展为包含性,而不是在 predicate 为false时进行独占。

public static IEnumerable<T> TakeWhile<T>(this IEnumerable<T> source, Func<T, bool> predicate, bool inclusive)
        {
            source.ThrowIfNull("source");
            predicate.ThrowIfNull("predicate");

            if (!inclusive)
                return source.TakeWhile(predicate);

            var totalCount = source.Count();
            var count = source.TakeWhile(predicate).Count();

            if (count == totalCount)
                return source;
            else
                return source.Take(count + 1);
        }

虽然这是可行的,但我确信有更好的方法,我相当肯定这在延迟执行/加载方面行不通。
ThrowIfNull()ArgumentNullException检查的扩展方法
社区可以提供一些提示或重写吗?:)

sdnqo3pr

sdnqo3pr1#

你说得对这对于延迟执行是不友好的(调用Count需要源的完整枚举)。
但是,您可以这样做:

public static IEnumerable<T> TakeWhile<T>(this IEnumerable<T> source, Func<T, bool> predicate, bool inclusive)
{
    foreach(T item in source)
    {
        if(predicate(item)) 
        {
            yield return item;
        }
        else
        {
            if(inclusive) yield return item;

            yield break;
        }
    }
}
zzoitvuj

zzoitvuj2#

这不是对这个问题的直接回答。我想展示如何使用SkipWhile来模拟包含TakeWhile逻辑。

IEnumerable<string> list = new List<string> { "1", "2", "3", "4", "5" };
var result = list
    .Reverse()
    .SkipWhile(item => item != "3")
    .Reverse();
// result will be {"1", "2", "3"}

但是要注意,这样做效率会比较低,因为本质上,在这种情况下,list必须反转两次。所以要确保性能不会成为问题。

gojuced7

gojuced73#

基本上与@adamrobinson的答案相同,只是签名不同,似乎与内置扩展一致,以防有人搜索TakeUntil

public static IEnumerable<T> TakeUntil<T>( this IEnumerable<T> source, Func<T, bool> predicate )
    {
        foreach ( var item in source )
        {
            yield return item;

            if ( predicate( item ) )
            {
                yield break;
            }
        }
    }

相关问题