Edit:
I looked a little closer. The WhereEnumerableIterator
returned by the Where
extension method actually overrides the Where
method and combines the predicates into a single callback.
public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) {
return new Enumerable.WhereEnumerableIterator<TSource>(
this.source,
Enumerable.CombinePredicates<TSource>(this.predicate, predicate));
}
private static Func<TSource, bool> CombinePredicates<TSource>(
Func<TSource, bool> predicate1, Func<TSource, bool> predicate2
) {
return (TSource x) => predicate1(x) && predicate2(x);
}
So, the speed difference I saw on my machine should probably be attributed to something else.
The first example will loop over the elements
collection once to find items that satisfy the condition item > 3
, and again to find items that satisfy the condition item % 2 == 0
.
The second example will loop over the elements
collection once to find items that satisfy the condition item > 3 && item % 2 == 0
.
In the examples provided, the second will most likely always be faster than the first, because it only loops over elements
once.
Here is an example of some pretty consistent results I get on my machine (.NET 3.5):
var stopwatch = new System.Diagnostics.Stopwatch();
var elements = Enumerable.Range(1, 100000000);
var results = default(List<int>);
stopwatch.Start();
results = elements.Where(n => n > 3).Where(n => n % 2 == 0).ToList();
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
stopwatch.Reset();
stopwatch.Start();
results = elements.Where(n => n > 3 && n % 2 == 0).ToList();
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
Console.WriteLine("Done");
Console.ReadLine();
Results:
00:00:03.0932811
00:00:02.3854886
Done
EDIT:
@Rawling is right in that my explanation only applies to LINQ as used on collections of POCO objects. When used as an interface to LINQ-to-SQL, NHibernate, EF, etc., your results will be more implementation-dependent.