首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >一旦结果不能再更改,C# LINQ聚合方法是否会结束执行?

一旦结果不能再更改,C# LINQ聚合方法是否会结束执行?
EN

Stack Overflow用户
提问于 2017-07-01 00:35:52
回答 3查看 925关注 0票数 4

我知道,如果我在同一条语句中将&&||运算符链接到一起,c#将停止计算该语句,并在计算表达式时返回适当的结果,并且无论下面的表达式是什么,结果都不会改变。例如:

代码语言:javascript
复制
var result = false && foo() && bar();

在此语句中,foo()bar()将永远不会执行,因为第一个表达式为false。我的问题是,当运行一组bool时,Enumerable.Aggregate<TSource, TAccumulate>会做同样的事情,还是会计算所有的表达式?例如:

代码语言:javascript
复制
var result = new List<bool>
{
    false,
    foo(),
    bar()
}.Aggregate(true, (acc, x) => acc && x);
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-07-01 00:40:49

是的,您示例中的&&操作符将会短路。当accfalse时,不会对x求值。

当然,每个元素都需要执行整个谓词。Aggregate不可能知道以后执行它不会改变聚合值。

聚合函数实际上是在数据集上执行All操作,如果使用All操作,而不是更通用的Aggregate操作,那么只要给定的谓词为false,它就能够确定结果是已知的且不能更改,并且不需要在其余元素上调用该谓词(当找到true值时,Or也是如此)。

票数 6
EN

Stack Overflow用户

发布于 2017-07-01 01:34:57

正如其他答案所指出的,您的聚合调用将遍历整个集合,但是每个调用上的&&将短路。这里有一个例子可以说明这一点:

您可以看到,在result1中,一旦得到错误的结果,它就会停止计算x()。这是由于acc短路造成的。

在result2中,我们将acc移到了&&的右边,它强制在所有情况下都对x()求值。

代码语言:javascript
复制
Console.WriteLine("acc && x()");
var result1 = new List<Func<bool>>
{
    () => {Console.WriteLine("One"); return true;},
    () => {Console.WriteLine("Two"); return false;},
    () => {Console.WriteLine("Three"); return false;}
}.Aggregate(true, (acc, x) => acc && x());
Console.WriteLine();
Console.WriteLine("x() && acc");
var result2 = new List<Func<bool>>
{
    () => {Console.WriteLine("One"); return true;},
    () => {Console.WriteLine("Two"); return false;},
    () => {Console.WriteLine("Three"); return false;}
}.Aggregate(true, (acc, x) => x() && acc);

输出:

代码语言:javascript
复制
acc && x()
One
Two

x() && acc
One
Two
Three
票数 0
EN

Stack Overflow用户

发布于 2018-06-13 07:19:35

根据另一个问题,我正在使用Aggregate,如果出现某个中间值,则需要提前退出,这最终涉及到许多三元运算符(或带有if的λ主体),以便在达到该值时绕过聚合,因此我编写了一些新的扩展以提前退出:

代码语言:javascript
复制
public static T AggregateWhile<T>(this IEnumerable<T> src, Func<T, T, T> accumFn, Predicate<T> whileFn) {
    using (var e = src.GetEnumerator()) {
        if (!e.MoveNext())
            throw new Exception("At least one element required by AggregateWhile");
        var ans = e.Current;
        while (whileFn(ans) && e.MoveNext())
            ans = accumFn(ans, e.Current);
        return ans;
    }
}

public static TAccum AggregateWhile<TAccum, T>(this IEnumerable<T> src, TAccum seed, Func<TAccum, T, TAccum> accumFn, Predicate<TAccum> whileFn) {
    using (var e = src.GetEnumerator()) {
        if (!e.MoveNext())
            throw new Exception("At least one element required by AggregateWhile");
        var ans = accumFn(seed, e.Current);
        while (whileFn(ans) && e.MoveNext())
            ans = accumFn(ans, e.Current);
        return ans;
    }
}

对于您的示例,您可以使用它,如下所示:

代码语言:javascript
复制
var result = new List<bool> {
    false,
    foo(),
    bar()
}.AggregateWhile(true, (acc, x) => acc && x, acc => acc);

当然,foo()bar()会被执行,因为List<bool>不会延迟执行,所以只节省了循环时间。但是如果你有一个这样的序列:

代码语言:javascript
复制
var result = new List<Func<bool>> { () => false, () => foo(), () => bar() }
             .AggregateWhile(true, (acc, f) => acc && f(), acc => acc);

这将跳过执行foobar

作为练习,留下了明显的对应AggregateUntil :)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44851218

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档