使用 LINQ 在条件下中断函数组合

Mat*_*haq 5 c# linq

是否有等效于以下的 LINQ?

static T Compose<T>(T source,
    IEnumerable<Func<T, T>> funcs,
    Func<T, bool> cond)
{
    foreach (var func in funcs)
    {
        source = func(source);

        if (cond(source)) break;
    }

    return source;
}

// This ends the composition as soon as a null is returned
var result = Compose(x, funcs, x => x == null);
Run Code Online (Sandbox Code Playgroud)

本质上,我希望将函数组合在一起,并在当前值匹配特定条件时中断。

result = f(g(h(x)))  // if condition is met somewhere within this chain,
                     // it will immediately break and return
Run Code Online (Sandbox Code Playgroud)

编辑:我想到了一些类似的东西

funcs.Aggregate(seed, (x, f) => cond(x) ? x : f(x));
Run Code Online (Sandbox Code Playgroud)

但这看起来令人困惑,并且最终会枚举整个集合,而不是在满足条件时中断。

Mat*_*haq 3

执行此操作的一种方法是Aggregate直到满足条件为止。因此,我定义了一个扩展方法:

public static TAccumulate AggregateUntil<TSource, TAccumulate>(
    this IEnumerable<TSource> source,
    TAccumulate seed,
    Func<TAccumulate, TSource, TAccumulate> func,
    Func<TAccumulate, bool> predicate)
{
    if (source == null)
        throw new ArgumentNullException(nameof(source));

    if (func == null)
        throw new ArgumentNullException(nameof(func));

    if (predicate == null)
        throw new ArgumentNullException(nameof(predicate));

    var accumulate = seed;
    foreach (var item in source)
    {
        accumulate = func(accumulate, item);
        if (predicate(accumulate)) break;
    }
    return accumulate;
}
Run Code Online (Sandbox Code Playgroud)

我们现在可以写成ComposeUntil:

public static T ComposeUntil<T>(
    this IEnumerable<Func<T, T>> source,
    T seed,
    Func<T, bool> predicate)
{
    return source.AggregateUntil(seed, (x, f) => f(x), predicate);
}
Run Code Online (Sandbox Code Playgroud)

并按以下方式使用它:

var funcs = new List<Func<int, int>>
{
    x => x + 1,
    x => x + 2,
    x => x + 3,
    x => x + 4
};

var result = funcs.ComposeUntil(0, x => x >= 6);
// result == 6
Run Code Online (Sandbox Code Playgroud)