203

I often see people using Where.FirstOrDefault() to do a search and grab the first element. Why not just use Find()? Is there an advantage to the other? I couldn't tell a difference.

namespace LinqFindVsWhere
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> list = new List<string>();
            list.AddRange(new string[]
            {
                "item1",
                "item2",
                "item3",
                "item4"
            });

            string item2 = list.Find(x => x == "item2");
            Console.WriteLine(item2 == null ? "not found" : "found");
            string item3 = list.Where(x => x == "item3").FirstOrDefault();
            Console.WriteLine(item3 == null ? "not found" : "found");
            Console.ReadKey();
        }
    }
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
KingOfHypocrites
  • 9,316
  • 9
  • 47
  • 69
  • 56
    FWIW, `list.FirstOrDefault(x => x == "item3");` is more concise than using both `.Where` and `.FirstOrDefault`. – Kirk Woll Feb 17 '12 at 20:39
  • @Kirk, I guess my next question would be why did they add the find at all. That is a good tip. The only thing I can think of is that the FirstOrDefault could return a different default value other than null. Otherwise it just seems like a pointless addition. – KingOfHypocrites Feb 17 '12 at 20:49
  • 9
    `Find` predates LINQ. (it was available in .NET 2.0 and you couldn't use lambdas. You were forced to use normal methods or anonymous methods) – Kirk Woll Feb 17 '12 at 20:52

7 Answers7

239

Where is the Find method on IEnumerable<T>? (Rhetorical question.)

The Where and FirstOrDefault methods are applicable against multiple kinds of sequences, including List<T>, T[], Collection<T>, etc. Any sequence that implements IEnumerable<T> can use these methods. Find is available only for the List<T>. Methods that are generally more applicable, are then more reusable and have a greater impact.

I guess my next question would be why did they add the find at all. That is a good tip. The only thing I can think of is that the FirstOrDefault could return a different default value other than null. Otherwise it just seems like a pointless addition

Find on List<T> predates the other methods. List<T> was added with generics in .NET 2.0, and Find was part of the API for that class. Where and FirstOrDefault were added as extension methods for IEnumerable<T> with Linq, which is a later .NET version. I cannot say with certainty that if Linq existed with the 2.0 release that Find would never have been added, but that is arguably the case for many other features that came in earlier .NET versions that were made obsolete or redundant by later versions.

Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
  • 100
    Just to complement: There is no need to call Where and First or FirstOrDefault: either First or FirstOrDefault allows you to specify a search predicate, making the Where call unnecessary – Robson Rocha de Araujo Jul 06 '12 at 23:45
  • 5
    But `Where(condition).FirstOrDefault()` optimizes at least as well and sometimes better than `FirstOrDefault(condition)` alone. We always use `Where()` to get the improved performance when available. – Suncat2000 Oct 09 '18 at 11:41
  • 15
    @Suncat2000 provide an example please – Konstantin Salavatov Aug 29 '19 at 16:27
  • 6
    @Suncat2000 You're using Linq becasue of its expressive power and want to write declarative code. You should not be concerned with such micro improvements, which also can change in future implementations. Also, don't optimize too early – Piotr Falkowski May 26 '20 at 15:54
  • 1
    @suncat2000 I would like to verify that claim because if it faster then wouldn't firstordefault(predicate) just be implemented as where(predicate).firstordefault(). – Wouter Nov 23 '22 at 01:39
75

I just found out today, doing some tests on a list of 80K objects and found that Find() can be up to 1000% faster than using a Where with FirstOrDefault().
I didn't know that until testing a timer before and after each call.
Sometimes it was the same time, otherwise, it was faster.

see this https://rules.sonarsource.com/csharp/RSPEC-6602

Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
digiben
  • 823
  • 6
  • 3
  • 8
    Did you try it with Where AND FirstOrDefault? If you did perhaps try it with just only FirstOrDefault and see if Find() is still better. – MVCKarl Nov 26 '12 at 11:08
  • 1
    @MVCKarl pls see [here](http://stackoverflow.com/questions/14032709/performance-of-find-vs-firstordefault). Find is really faster almost twice. But I can't figure out is this due to no Enumerator overhead only? – Arman Dec 25 '12 at 17:36
  • 8
    That sounds like you did not materialise the result with a `.ToList()` or `.ToArray()` to actually perform the query. – Andrew Morton Dec 15 '15 at 09:18
  • 6
    It is because `Find` makes use of the primary keys (hence indexes), whereas `Where` is a plain sql query – percebus Feb 09 '16 at 19:56
  • 4
    As of EF6, Find and FirstOrDefault both generate exactly the same SQL statements. You can see the SQL in a console app by doing context.Database.Log = Console.Write; The sited example is using in-memory "Find" against a list of strings, not going against a DB with primary keys. Perhaps the statement translation of the Find clause - which omits the need to do lambda expression parsing is the reason for the performance improvement in this case. Against a database I doubt you'll notice a difference in RL situations... I also wonder if it was tested using Find first instead of second... – C.List Oct 23 '17 at 18:27
  • 4
    Well, this performance improvement is because find() check in cache for object before hitting DB whereas where() always to go DB to get object – Gaurav Apr 19 '18 at 10:56
  • 1
    This pertains to LINQ-to-Entities, rather than LINQ-to-objects as specified by the original poster. – Suncat2000 Oct 09 '18 at 11:44
50

There is a very important difference if the source of the data is Entity Framework: Find will find entities in the 'added' state that are not yet persisted, but Where will not. This is by design.

Chalky
  • 1,624
  • 18
  • 20
31

Find is only implemented in List<T>, while Where().FirstOrDefault() works with all IEnumerable<T>.

penartur
  • 9,792
  • 5
  • 39
  • 50
1

For LINQ-2-Objects, there is no difference between something like items.FirstOrDefault(item => item.Id == id) and items.Find(item => item.Id == id), since both enumerate over all items until a match is found. There can be performance differences when items.Find(id), which can use a hashtable to find an object rather than using an iterator. So I guess to make performance measurements where this is an issue.

More importantly is the difference in behaviour when using EntityFramework, since .FirstOrDefault() executes a query and adds the result to the change tracker (by default; use .AsTracking()/.AsNoTracking() and the settings of the DBContext for override). The execution of .FirstOrDefault() might fail with an exception, when the object is already tracked by the change tracker.

.Find() will return the object that is already tracked by the change tracker in memory (ie. after an update or add). So this will not cause a problem when the object is already tracked.

MovGP0
  • 7,267
  • 3
  • 49
  • 42
-1

in addition to Anthony answer Where() visit through all records and then return result(s) while Find() dont need to traverse through all records if predicate match with given predicate.

so say you have List of Test class having id and name properties.

 List<Test> tests = new List<Test>();
 tests.Add(new Test() { Id = 1, Name = "name1" });
 tests.Add(new Test() { Id = 2, Name = "name2" });
 tests.Add(new Test() { Id = 3, Name = "name3" });
 tests.Add(new Test() { Id = 4, Name = "name2" }); 
 var r = tests.Find(p => p.Name == "name2");
 Console.WriteLine(r.Id);

Will give output of 2, and only 2 visits Find needed to give result , but if you use Where().FirstOrDefault() we will be visiting all records and then we get results.

So , when you know you only want first result from records in collection Find() will be more suitable then Where().FirstOrDefault();

aevitas
  • 3,753
  • 2
  • 28
  • 39
  • 10
    _but if you use Where().FirstOrDefault() we will be visiting all records and then we get results._ Nope. `FirstOrDefault` will 'bubble-up' the chain and stop enumerating everything. I use the term 'bubble-up' for lack of a better expression, because actually every selector/predicate will be passed on to the next, so the last method in the chain is actually doing work first. – Silvermind Jul 17 '19 at 13:40
  • 1
    Which means: this answer misses the mark completely. – Gert Arnold Dec 15 '20 at 13:20
  • I don't understand why to use Where(condition).FirstOrDefault(). This checks all the records and THEN filters the result. I guess it is NOT THE SAME thing as direct FirstOrDefault(condition) which should stop the search at the first valid record. – tedebus Sep 07 '21 at 10:01
  • The reason why Find() faster than the others, thanks! – ilyas varol Dec 04 '21 at 11:03
-1

Find() is the IEnumerable equivalent of a FirstOrDefault(). You should not chain both .Where() with .FirstOrDefault() because the .Where() goes through the whole array and then will iterate through that list to find the first item. You save an incredible amount of time by putting your search predicate in the FirstOrDefault() method.

Also, I encourage you to read the linked question to this thread to know more about the better performances on using the .Find() in specific scenarios Performance of Find() vs. FirstOrDefault()

Whiplash
  • 177
  • 3
  • 16