1

I wonder if there is a difference between the following statements in respect to both performance and calling-style(e.g. applied the expression to all sequences or objects).

var minPrice = SampleData.Books
                               .Min(book => book.Price);
var maxPrice = SampleData.Books
                               .Select(book => book.Price)
                               .Max();

or

var nbCheapBooks1 = SampleData.Books
                                    .Select(book => book.Price)
                                    .Where(book => book < 30).Count();

var nbCheapBooks2 = SampleData.Books
                                    .Select(book => book.Price)
                                    .Count(book => book < 30);

var nbCheapBooks3 = SampleData.Books
                                    .Count(book => book.Price < 30);
  • What is the runtime type of `SampleData.Books`? That might be significant. [LINQ performance Count vs Where and Count](https://stackoverflow.com/q/25787555/150605) compares `.Count()` with `.Where().Count()` for a `List<>`. And can you elaborate on the "calling-style" part of your question? It seems like any differences there should be apparent. Also, for clarity, after you do `.Select(book => book.Price)` I think subsequent lambda variables should be named `price`, not `book`. Also related: [Difference between Where().Count() and Count()](https://stackoverflow.com/q/23863853/150605) – Lance U. Matthews Apr 15 '20 at 22:09

2 Answers2

2

Just created a simple benchmark, based on your sample, and added one more method with filtering using Where(book => book.Price < 30) and count (which should be the fastest one)

[SimpleJob]
public class LinqBenchmark
{
    private IEnumerable<Book> Books;

    [GlobalSetup]
    public void Setup()
    {
        Books = new List<Book>()
        {
            new Book { Price = 20 },
            new Book { Price = 30 },
            new Book { Price = 40 },
            new Book { Price = 50 },
            new Book { Price = 60 },
            new Book { Price = 70 },
            new Book { Price = 80 },
            new Book { Price = 10 }
        };
    }

    [Benchmark]
    public int SelectWhereCount()
    {
        return Books.Select(book => book.Price).Where(book => book < 30).Count();
    }

    [Benchmark]
    public int SelectCount()
    {
        return Books.Select(book => book.Price).Count(book => book < 30);
    }

    [Benchmark]
    public int WhereCount()
    {
        return Books.Where(book => book.Price < 30).Count();
    }

    [Benchmark]
    public int Count()
    {
        return Books.Count(book => book.Price < 30);
    }

    internal class Book
    {
        public int Price { get; internal set; }
    }
}

Count method with predicate works faster then other ones

enter image description here

You can refer to implementation details to see and understand a performance difference. Count(book => book.Price < 30) pass each element in a loop to Func<TSource, bool> predicate and increments count, if gets true.

Where and Select under the hood use special WhereSelectEnumerableIterator or WhereListIterator class and then calculate the count. The reason why Where and Count works faster is perfectly explained in LINQ performance Count vs Where and Count thread, leave it here for the reference.

So, in terms of performance Books.Where(book => book.Price < 30).Count() is fastest option, in terms of readability two last options look more convenient, IMO.

Pavel Anikhouski
  • 21,776
  • 12
  • 51
  • 66
0

They are functionaly equivalent. I would prefer the shorter variants, i.e. .Count(book => book.Price < 30) simply because it is shorter. There might be some slight difference in performance. But if performance is the most important concern, a regular for-loop is usually faster, but less convenient and readable.

If you want to know the actual performance difference, test it. Insert a stopwatch and measure the execution time.

JonasH
  • 28,608
  • 2
  • 10
  • 23