首页 > 解决方案 > 通过与 Select 链接使用聚合运算符与不这样做之间的区别

问题描述

我想知道以下语句在性能和调用风格方面是否存在差异(例如,将表达式应用于所有序列或对象)。

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

或者

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);

标签: c#linqconditional-statementsaggregate-functions

解决方案


刚刚根据您的样本创建了一个简单的基准测试,并添加了一种使用Where(book => book.Price < 30)和计数进行过滤的方法(这应该是最快的方法)

[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带有谓词的方法比其他方法工作得更快

在此处输入图像描述

您可以参考实现细节来查看和了解性能差异。Count(book => book.Price < 30)如果得到,则将循环中的每个元素传递给Func<TSource, bool> predicate并递增计数true

WhereSelect在引擎盖下使用特殊WhereSelectEnumerableIteratorWhereListIterator类,然后计算计数。LINQ performance Count vs Where and Count thread中完美解释了工作速度更快的原因Where,将其留在这里以供参考。Count

因此,就性能而言Books.Where(book => book.Price < 30).Count()是最快的选项,就可读性而言,最后两个选项看起来更方便,IMO。


推荐阅读