2010-03-16 56 views
8

先执行()执行OrderBy()?

var a = Orders.OrderBy(order => order.Date).First() 

var y = Orders.Where(order => order.Date == Orders.Min(x => x.Date)).ToList(); 

即之间(渐近)性能的任何差异将首先()执行的OrderBy()?我猜不。 MSDN表示通过foreach或GetEnumerator枚举集合,但该语句不排除其他扩展。

+1

顺便说一下,正如Guffa所说,这两者并不完全相同 - 第二种选择可以返回多个值,第一个选项不能。 – 2013-04-09 00:04:43

回答

7

有几件事情:

  • OrderBy()订单从小到大,所以你的两个备选方案的不同元素
  • Where()通常是懒惰的,所以你的第二个表现实际上并没有做任何计算的话 - 直到使用。
  • 原则上,有问题的行为取决于查询提供者。例如,您可能确实希望sql-server linq查询提供程序以与IEnumerable查询提供程序不同的方式处理此问题。查询提供者可能会选择使“OrderBy”的返回值具有足够的专用性,以致在其上调用First()可以识别(在编译或运行时)它在有序枚举上运行,而不是排序,选择返回(第一)最小元素。
  • 专门为IEnumerable<T>提供商,OrderBy恰好返回一个枚举,充分的缓冲液和每一个第一元件被检索时间排序输入 - 因此,在共同的基本LINQ到对象的情况下,OrderBy().First()比得上OrderBy().ToArray()

Remeber是LINQ只是一堆函数名的 - 每个供应商可能会选择不同的方式实现这些,因此,上述仅持有的System.Linq的IEnumerable的查询提供,而不一定是别人。

+0

我明白了。我认为linq2sql可能会优化第一条语句的sql。如果不是sql-server可能会优化解释。如果不是,那么我很快就会发现。对? – Martin 2010-03-16 17:05:48

+0

实际上,尝试是一种很好的方法,可以很快发现:-) - 但是的确,这听起来对我来说很合适。 – 2010-03-17 15:29:11

0

它没有。这是说 - 自然顺序将执行的时刻有人试图实际获得第一个元素。

但正如您所说,条件可能会进一步定义。因此,不 - 它不会在那时执行。

+0

虽然你在技术上是正确的,但我觉得你给OP给了错误的印象。 – Blindy 2010-03-16 14:25:01

+1

但First()实际上是获取第一个元素,所以我确信第一行确实会执行OrderBy – CodingInsomnia 2010-03-16 14:26:20

+0

虽然这是真的,但这并不是什么区别。第二个查询中的While将不会执行,直到有人真正得到结果为止。 – Guffa 2010-03-16 14:36:38

5

First将返回传递给它的IEnumerable的第一个条目。由于IEnumerable传递给FirstOrderBy的结果,所以您的问题可以改为“是否OrderBy工作”,并且是的。

First无法推迟执行OrderBy,因为它立即返回结果。例如:

 var numbers = new int[] { 9, 3, 4, 6, 7 }; 

     var num = numbers.First(); 
     Console.WriteLine(num); 

     num = numbers.OrderBy(i => i).First(); 
     Console.WriteLine(num); 

     Console.ReadLine(); 
+0

上述不再适用于.NET 4.7.1。 OrderBy返回一个OrderedEnumerator,但它实际上并没有对返回的列表进行排序。 当您调用First()时,它只需查看对象,然后提出将是第一个的项目,这就是它现在所做的事情,而不会打扰实际排序列表。如果列表已经排序,它似乎也是O(n)。 见 为清楚起见https://github.com/dotnet/corefx/blob/ed0ee133ac49cee86f10ca4692b1d72e337bc012/src/System.Linq/src/System/Linq/OrderedEnumerable.cs – 2017-12-05 15:23:42

6

First方法执行OrderBy(即,给定First方法当然执行)。当First方法从OrderBy的结果中抽取第一个项目时,它必须对所有项目进行排序以找出哪一个是第一个项目。

根据查询运行的地点和方式(即如果查询引擎无法围绕它进行优化),第二个查询可能执行得相当糟糕。如果Orders.MaxOrders中的每个项目评估一次,它将变成O(n * n)操作,这非常糟糕。

还有一个功能差异,如果有重复的日期,第二个查询可以返回多个项目。

+0

添加任务。它会立即执行,不是吗? – Martin 2010-03-16 17:00:33

+0

@Martin:第一个将执行,但不是第二个。第一个将得到第一个项目并分配给变量,但第二个将创建一个可以返回结果的表达式。表达式不会执行,直到您从中读取结果为止,例如:'列表 earlyOnes = y.ToList();'。 – Guffa 2010-03-16 17:23:35

+0

添加了tolist。 :) – Martin 2010-03-16 17:40:28