none
Where(predicate).FirstOrDefault() VS FirstOrDefault(predicate) for lists and arrays RRS feed

  • General discussion

  • Recently my colleague sent me a link to a development blog.  Among others, one of the statements in this post was that one should use .Where(predicate).First() rather than .First(predicate) for collections. The reason for that is that the first way is faster.

    Being more than skeptical about this I've decided to test and found that it's really true. The gain of using Where().First() is ~10-15% for List<T> and ~20-25% for T[] on my machine. Just to mention, no difference between First and FirstOrDefault - the results are the same.

    The code snippet I've used for testing follows:

    class Program
        {
            private class MyElement
            {
                public string Value { get; set; }
            }
    
            static void Main(string[] args)
            {
                var numberOfElements = 500000;
                var numberOfSearches = 1000;
                var numberOfExperiments = 10;
                var collection = new MyElement[numberOfElements]; // new List<MyElement>(numberOfElements)
    
                for (var i = 0; i < numberOfElements; i++)
                {
                    collection[i] = new MyElement {Value = Guid.NewGuid().ToString()};
                }
    
                for (var j = 0; j < numberOfExperiments; ++j)
                {
                    var random = new Random();
                    var elementsToSearchFor = new string[numberOfSearches];
    
                    for (var i = 0; i < numberOfSearches; i++)
                    {
                        elementsToSearchFor[i] = collection[random.Next(2 * numberOfElements / 3, numberOfElements)].Value;
                    }
    
                    var results = new MyElement[numberOfSearches];
    
                    var wherePlusFirstTimer = new Stopwatch();
                    wherePlusFirstTimer.Start();
    
                    for (var i = 0; i < numberOfSearches; ++i)
                    {
                        results[i] = collection.Where(e => e.Value == elementsToSearchFor[i]).FirstOrDefault();
                    }
    
                    wherePlusFirstTimer.Stop();
    
                    var firstTimer = new Stopwatch();
                    firstTimer.Start();
    
                    var whereToSearch = (IEnumerable<MyElement>)collection;
    
                    for (var i = 0; i < numberOfSearches; ++i)
                    {
                        results[i] = whereToSearch.FirstOrDefault(e => e.Value == elementsToSearchFor[i]);
                    }
    
                    firstTimer.Stop();
    
                    Console.Out.WriteLine("Where().First(): {0} ms; First(): {1} ms.", wherePlusFirstTimer.ElapsedMilliseconds, firstTimer.ElapsedMilliseconds);
                }
            }
        }

    There are some differences in the internal iterators for List<T> and Array<T> comparing to the ones used for Where extension method (like checking for List version to prevent modifying collection while iterating or using struct instead of class).

    So I have two questions:

    1. Does anyone knows the reason why "standard" List and Array iterators performance was not improved?

    2. Why FirstOrDefault(predicate) can't use the same iterator as Where(predicate) uses?





    Thursday, December 19, 2013 7:33 PM

All replies

  • Hi,

    I would use First when I know or expect the sequence to have at least one element. In other words, when it is an exceptional occurence when the sequence is empty.

    Use FirstOrDefault, when you know that you will need to check whether there was an element or not. In other words, when it is legal for the sequence to be empty. You should not rely on exception handling for the check. (It is bad practice, and might hurt performance).


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, December 23, 2013 6:09 AM
    Moderator