作为一个天真的提示,你经常听到使用IEnumerable.Any(),因为那样就不一定需要遍历整个可枚举。
我刚写了一小段代码,试图查看Enumerable是否包含单个项目或多个项目。
if (reportInfo.OrebodyAndPits.SelectMany(ob => ob.Pits).Count() > 1)
{
ws.Cells[row, col++].Value = "Pits";
}
else
{
ws.Cells[row, col++].Value = "Pit";
}
这让我想知道,比较是否会编译成一个足够聪明的形式,一旦枚举超过第一个项目就会返回false?
如果没有,有没有办法编写一个能做到这一点的linq扩展方法?
(请注意,我对这段代码的性能影响并不十分感兴趣。我主要感到好奇。)
答案 0 :(得分:4)
不,它不会。您的代码将计算序列中的所有项目。这是因为编译器没有对LINQ语句进行优化,你所写的是你得到的。
检查序列是否包含多于1个项目的公平,更有效的方法是:
reportInfo.OrebodyAndPits.SelectMany(ob => ob.Pits).Skip(1).Any();
这将在跳过第一个项目后检查是否还有任何项目。
答案 1 :(得分:3)
如果您想知道某些内容是如何工作的,为什么不查看源代码?
以下是Any()
方法:https://github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/AnyAll.cs#L20
以下是Count()
方法:https://github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/Count.cs#L12
编译器无法像您描述的那样进行优化。它要求计数并获得一个数字,然后将该数字与条件语句中的数字进行比较。
然而,它会尝试进行某种优化。正如您从Count()
方法中看到的那样,它会尝试查看IEnumerable
是否已经支持Count
属性并使用它,因为它比再次计算所有元素更快。如果不可用,它必须遍历整个事物并逐个计算。
如果你想编写一个LINQ方法(它只是IEnumerable<T>
上的一个扩展方法),它确定IEnumerable中是否至少有两个,那么这应该很容易。像这样:
e.g。
public static bool AtLeastTwo<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull(nameof(source));
}
using (IEnumerator<TSource> e = source.GetEnumerator())
{
e.MoveNext(); // Move past the first one
return e.MoveNext(); // true if there is at least a second element.
}
}