2010-03-16 1 views
8

Có sự khác biệt trong hoạt động (tiệm cận) giữaĐầu tiên() sẽ thực hiện OrderBy()?

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

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

ví dụ sẽ First() thực hiện các OrderBy()? Tôi đoán không. MSDN cho biết liệt kê bộ sưu tập thông qua công cụ GetEnumerator foreach, nhưng cách phân tích không loại trừ các phần mở rộng khác.

+1

Là một sang một bên, và như Guffa đã nói, cả hai đều không giống nhau - tùy chọn thứ hai có thể trả lại nhiều giá trị, giá trị đầu tiên không thể. –

Trả lời

7

Một vài điều:

  • OrderBy() đơn đặt hàng từ nhỏ đến lớn, vì vậy hai lựa chọn thay thế của bạn trở lại các yếu tố khác nhau
  • Where() thường lười biếng, vì vậy biểu hiện thứ hai của bạn không thực sự làm bất cứ tính toán ở tất cả - không cho đến khi sử dụng.
  • Về nguyên tắc, hành vi được đề cập tùy thuộc vào nhà cung cấp truy vấn. Ví dụ, bạn thực sự có thể mong đợi nhà cung cấp truy vấn LINQ-server để giải quyết vấn đề này khác với nhà cung cấp truy vấn IEnumerable. Nhà cung cấp truy vấn có thể chọn để có giá trị trả về của "OrderBy" đủ chuyên biệt để gọi số First() trên đó nhận ra (hoặc lúc biên dịch hoặc chạy) mà nó chạy trên một số được sắp xếp và thay vì sắp xếp, chọn trả về (đầu tiên) yếu tố tối thiểu.
  • Cụ thể đối với các nhà cung cấp IEnumerable<T>, OrderBy xảy ra để trả lại một đếm được có đủ bộ đệm và sắp xếp các đầu vào mỗi khi yếu tố đầu tiên được lấy ra - vì vậy, trong cơ bản LINQ-to-đối tượng trường hợp thông thường, OrderBy().First() được so sánh với OrderBy().ToArray().

Hãy nhớ rằng LINQ chỉ là một loạt tên hàm - mỗi nhà cung cấp có thể chọn triển khai các cách khác nhau, vì vậy ở trên chỉ giữ cho nhà cung cấp truy vấn System.Linq IEnumerable và không nhất thiết phải là người khác.

+0

Tôi hiểu. Tôi tưởng tượng rằng linq2sql có thể tối ưu hóa sql cho câu lệnh đầu tiên. Nếu không sql-server có thể tối ưu hóa việc giải thích. Nếu không, thì tôi sẽ sớm tìm ra. Đúng? – Martin

+0

Thực sự cố gắng là một cách tốt để sớm tìm ra thực sự :-) - nhưng chắc chắn, điều đó nghe có vẻ đúng với tôi. –

0

Nó không. R BENG S BE ĐƯỢC SAI - một cách tự nhiên, thứ tự sẽ thực hiện ngay khi ai đó cố thực sự GET phần tử đầu tiên.

Nhưng như bạn đã nói, các điều kiện có thể được xác định thêm. Như vậy, không - nó không thực hiện tại thời điểm đó.

+0

Mặc dù bạn chính xác về mặt kỹ thuật, tôi cảm thấy bạn đang gây ấn tượng sai với OP. – Blindy

+1

Nhưng First() thực sự nhận được phần tử đầu tiên vì vậy tôi khá chắc chắn rằng hàng đầu tiên thực sự sẽ thực hiện OrderBy – CodingInsomnia

+0

Trong khi đúng, nó không phải là một sự khác biệt. Trong khi trong truy vấn thứ hai sẽ không thực thi cho đến khi ai đó thực sự nhận được kết quả. – Guffa

5

First sẽ trả lại mục nhập đầu tiên của IEnumerable được chuyển cho nó. Vì IEnumerable được chuyển đến First là kết quả của OrderBy câu hỏi của bạn có thể được lặp lại thành "Có OrderBy hoạt động" hay không, và có.

First không thể trì hoãn việc thực thi OrderBy vì nó trả về kết quả ngay lập tức. Ví dụ:

 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

Ở trên không còn đúng đối với .NET 4.7.1. OrderBy trả về một OrderedEnumerator, nhưng nó đã không thực sự ra lệnh cho danh sách trở lại. Khi bạn gọi First(), nó chỉ cần nhìn qua các đối tượng, và tìm ra mục sẽ là đầu tiên, và đó là những gì nó bây giờ làm, không bận tâm để thực sự sắp xếp danh sách. Nó cũng có vẻ là O (n) nếu danh sách đã được sắp xếp. Xem https://github.com/dotnet/corefx/blob/ed0ee133ac49cee86f10ca4692b1d72e337bc012/src/System.Linq/src/System/Linq/OrderedEnumerable.cs –

6

Phương pháp First sẽ thực hiện OrderBy (có nghĩa là, cho rằng phương pháp First được thực hiện tất nhiên). Khi phương pháp First kéo mục đầu tiên từ kết quả của OrderBy, nó sẽ phải sắp xếp tất cả các mục để tìm ra mục nào là mục đầu tiên.

Tùy thuộc vào vị trí và cách truy vấn được chạy (tức là nếu công cụ truy vấn không thể tối ưu hóa xung quanh nó), truy vấn thứ hai có thể hoạt động khá kém. Nếu Orders.Max được đánh giá một lần cho mỗi mục trong Orders, nó sẽ trở thành một hoạt động O (n * n), điều này khá tệ.

Có sự khác biệt về chức năng, truy vấn thứ hai có thể trả về nhiều mục nếu có ngày trùng lặp.

+0

Đã thêm bài tập để làm rõ. Nó sẽ thực hiện ngay bây giờ, phải không? – Martin

+0

@Martin: Người đầu tiên sẽ thực hiện nhưng không phải là người thứ hai. Người đầu tiên sẽ nhận được mục đầu tiên và gán cho biến, nhưng cái thứ hai sẽ tạo ra một biểu thức có thể trả về kết quả. Biểu thức sẽ không thực hiện cho đến khi bạn đọc kết quả từ nó, ví dụ: 'Danh sách earlyOnes = y.ToList();'. – Guffa

+0

Đã thêm tolist. :) – Martin