Search code examples
c#performancelinqilist

Linq count vs IList count


If I have the following IEnumerable list which comes from some repository.

IEnumerable<SomeObject> items = _someRepo.GetAll();

What is faster:

items.Count(); // Using Linq on the IEnumerable interface.

or

List<SomeObject> temp = items.ToList<SomeObject>(); // Cast as a List

temp.Count(); // Do a count on a list

Is the Linq Count() faster or slower than casting the IEnumerable to a List and then performing a Count()?

Update: Improved the question a little bit to a bit more realistic scenario.


Solution

  • Calling Count directly is a better choice.

    Enumerable.Count has some performance improvements built in that will let it return without enumerating the entire collection:

    public static int Count<TSource>(this IEnumerable<TSource> source) {
        if (source == null) throw Error.ArgumentNull("source");
        ICollection<TSource> collectionoft = source as ICollection<TSource>;
        if (collectionoft != null) return collectionoft.Count;
        ICollection collection = source as ICollection;
        if (collection != null) return collection.Count;
        int count = 0;
        using (IEnumerator<TSource> e = source.GetEnumerator()) {
            checked {
                while (e.MoveNext()) count++;
            }
        }
        return count;
    }
    

    ToList() uses similar optimizations, baked into List<T>(IEnumerable<T> source) constructor:

    public List(IEnumerable<T> collection) {
        if (collection==null)
            ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
        Contract.EndContractBlock();
    
        ICollection<T> c = collection as ICollection<T>;
        if( c != null) {
            int count = c.Count;
            if (count == 0)
            {
                _items = _emptyArray;
            }
            else {
                _items = new T[count];
                c.CopyTo(_items, 0);
                _size = count;
            }
        }    
        else {                
            _size = 0;
            _items = _emptyArray;
            // This enumerable could be empty.  Let Add allocate a new array, if needed.
            // Note it will also go to _defaultCapacity first, not 1, then 2, etc.
    
            using(IEnumerator<T> en = collection.GetEnumerator()) {
                while(en.MoveNext()) {
                    Add(en.Current);                                    
                }
            }
        }
    }
    

    But as you can see it only uses generic ICollection<T>, so if your collection implements ICollection but not its generic version calling Count() directly will be much faster.

    Not calling ToList first also saves you an allocation of new List<T> instance - not something overly expensive, but it's always better to avoid unnecessary allocation when possible.