聚合值直到达到限制

Hap*_*mad 6 c# linq linq-to-objects

我需要类似于AggregateWhile方法的东西。标准System.Linq.Enumerable类不提供它。到现在为止,我一直能够利用标准的 LINQ 方法来解决我遇到的每个问题。所以我想知道在这种情况下这是否仍然可行,或者我是否真的需要使用非标准方法扩展 LINQ。

假设的AggregateWhile方法将迭代一个序列并应用累加器。一旦谓词返回false,聚合就会完成。结果是元素的聚合,直到但包括谓词失败的元素。

这是一个例子。我们有一个List { 1, 2, 3, 4, 5 }带累加器的累加器,它将两个输入数字相加,以及一个声明累加必须小于 12 的谓词。 AggregateWhile将返回 10,因为这是 1 + 2 + 3 + 4 的结果,并且添加最后的 5 将推动总量超限。在代码中:

var list = new List<int> { 1, 2, 3, 4, 5 };
int total = list.AggregateWhile( (x, y) => x + y, a => a < 12 ); // returns 10
Run Code Online (Sandbox Code Playgroud)

我需要一个纯函数式解决方案,因此关闭临时变量不是一种选择。

slo*_*oth 4

您可以自己编写该函数,也可以在累加器中携带一个标志:

int total = list.Aggregate(new { value = 0, valid = true }, 
                          (acc, v) => acc.value + v < 12 && acc.valid ?
                                      new { value = acc.value + v, valid = true } :
                                      new { value = acc.value, valid = false },
                            acc => acc.value); 
Run Code Online (Sandbox Code Playgroud)

它很丑陋,所以写一个新的AggregateWhile会更好:

public static TSource AggregateWhile<TSource>(this IEnumerable<TSource> source, 
                                         Func<TSource, TSource, TSource> func,
                                         Func<TSource, bool> predicate)
{
   using (IEnumerator<TSource> e = source.GetEnumerator()) {
       TSource result = e.Current;
       TSource tmp = default(TSource);
       while (e.MoveNext() && predicate(tmp = func(result, e.Current))) 
            result = tmp;
       return result;
   }
}
Run Code Online (Sandbox Code Playgroud)

(为简洁起见,没有错误检查)