83

I am doing some performance tests and noticed that a LINQ expression like

result = list.First(f => f.Id == i).Property

is slower than

result = list.Where(f => f.Id == i).First().Property

This seems counter intuitive. I would have thought that the first expression would be faster because it can stop iterating over the list as soon as the predicate is satisfied, whereas I would have thought that the .Where() expression might iterate over the whole list before calling .First() on the resulting subset. Even if the latter does short circuit it should not be faster than using First directly, but it is.

Below are two really simple unit tests that illustrate this. When compiled with optimisation on TestWhereAndFirst is about 30% faster than TestFirstOnly on .Net and Silverlight 4. I have tried making the predicate return more results but the performance difference is the same.

Can any one explain why .First(fn) is slower than .Where(fn).First()? I see a similar counter intuitive result with .Count(fn) compared to .Where(fn).Count().

private const int Range = 50000;
private class Simple
{
 public int Id { get; set; }
 public int Value { get; set; }
}
[TestMethod()]
public void TestFirstOnly()
{
 List<Simple> list = new List<Simple>(Range);
 for (int i = Range - 1; i >= 0; --i)
 {
 list.Add(new Simple { Id = i, Value = 10 });
 }
 int result = 0;
 for (int i = 0; i < Range; ++i)
 {
 result += list.First(f => f.Id == i).Value;
 }
 Assert.IsTrue(result > 0);
}
[TestMethod()]
public void TestWhereAndFirst()
{
 List<Simple> list = new List<Simple>(Range);
 for (int i = Range - 1; i >= 0; --i)
 {
 list.Add(new Simple { Id = i, Value = 10 });
 }
 int result = 0;
 for (int i = 0; i < Range; ++i)
 {
 result += list.Where(f => f.Id == i).First().Value;
 }
 Assert.IsTrue(result > 0);
}
asked Dec 29, 2011 at 4:07
11
  • 6
    Your initial thought is wrong though: LINQ does lazy compute, so when First() is called it will query (the return value of) Where(...) for just one match and never ask for another. So the exact same number of elements will be examined as when you call First(...) (i.e. directly with a predicate). Commented Dec 29, 2011 at 4:16
  • 2
    I get the same result, .Where().First() is .021 seconds and .First() is .037 seconds. This is with a simple list of ints. Commented Dec 29, 2011 at 4:20
  • 5
    Here's proof on IdeOne, which is much faster than my computer. Commented Dec 29, 2011 at 4:21
  • As per my test it also depend upon which element you looking for.Just try with specific i value when you apply Where and first predicate. I try with value 1 and later 4999. I see diffrence in result. It seems that First loop through each item and match for perticular predicate until it match. Commented Dec 29, 2011 at 4:40
  • 5
    @minitech You didn't call Reset() on your stopwatch; your test actually shows that First() being significantly faster. Commented Dec 29, 2011 at 5:06

1 Answer 1

54

I got the same results: where+first was quicker than first.

As Jon noted, Linq uses lazy evaluation so the performance should be (and is) broadly similar for both methods.

Looking in Reflector, First uses a simple foreach loop to iterate through the collection but Where has a variety of iterators specialised for different collection types (arrays, lists, etc.). Presumably this is what gives Where the small advantage.

answered Dec 29, 2011 at 5:40

9 Comments

But if I was a framework developer and just implemented First(fn) internally as return Where(fn).First() it will work exactly as the current implementation of First except faster! Seems like a bad oversight on Microsoft's part.
Quite. I guess nobody's ever thought about it.
Also compare .Count(fn) with .Where(fn).Count(). The latter is faster due to the use of specialized iterators rather than the foreach used by .Count(fn) Using the convenience methods like .First(fn) and .Count(fn) leads to more concise code so seems like the right thing to do, but the .Where(fn).Method() is measurably faster. Grrrr!
Have a look at dotnetfiddle.net/k11nX6, you will be surprised that the answer is wrong.
Try this now !!! dotnetfiddle.net/OrUUSG , your answer is wrong !!! try any combination and prove your answer right.The real answer is Where enumerable caches Enumerable that is advantage over old List/Array iterator, but that has nothing to do with what is fast.
|

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.