2010-02-14 33 views
7

Giả sử tôi có một danh sách các mục (ví dụ: Bài đăng) và tôi muốn tìm mục đầu tiên theo một số thứ tự không tầm thường (ví dụ: PublishDate và sau đó là CommentsCount là bộ ngắt kết nối). Cách tự nhiên để làm được điều này với LINQ là như thế này:Cách tìm mục đầu tiên theo một thứ tự cụ thể bằng LINQ trong O (n)?

posts.OrderBy(post => post.PublishDate).ThenBy(post => post.CommentsCount).First() 

Tuy nhiên,-ưu vi trong tôi đang lo lắng rằng gọi OrderBy thực sự chi phí cho tôi O (n * LGN) để phân loại toàn bộ danh sách, khi tất cả Tôi thực sự cần là một hoạt động tìm kiếm tối thiểu O (n).

Vì vậy, LINQ có đủ thông minh để trả lại thứ gì đó từ OrderBy() biết cách tối ưu hóa các cuộc gọi First() tiếp theo không? Nếu không, cách tốt nhất để thực hiện việc này là gì? (Tôi luôn có thể viết thực hiện FindMinimumItem của riêng mình nhưng điều đó có vẻ như quá mức cần thiết).

+0

nếu chìa khóa thực sự là như in bạn không cần ThenBy nhưng thay vào đó có thể tạo ra một chìa khóa coumpund của cả hai. Mà sẽ được dễ dàng kể từ khi người đầu tiên hoặc là một dài (đánh dấu) hoặc một cố định với chuỗi. và đó sẽ là Inf (O) mà bạn yêu cầu nhưng sau đó một lần nữa không có bảo đảm rằng O (n) là nhanh hơn O (nlogn) –

Trả lời

2

Các phân loại là thông minh trong cách mà nó sẽ chỉ làm ThenBy vào nhóm đầu tiên từ OrderBy, nhưng OrderBy vẫn phải sắp xếp tất cả các mục trước khi nó có thể trả về nhóm đầu tiên.

Bạn có thể sử dụng phương pháp tổng hợp để có được những bài viết đầu tiên theo một so sánh tùy chỉnh: (. Giả sử rằng bạn đang sử dụng LINQ to Objects tất nhiên)

Post lowest = 
    posts.Aggregate((Post)null, 
    (x, y) => 
     x == null 
     || y.PublishDate < x.PublishDate 
     || (y.PublishDate == x.PublishDate && y.CommentsCount < x.CommentsCount) 
     ? y : x 
); 

+0

Cảm ơn, đó là một giải pháp tốt mặc dù một chút tiết. – Avish

0

Thường là max hoặc min (Tôi không biết nó được gọi như thế nào trong LinQ), được cung cấp một khóa cụ thể; phân loại và nhận được đầu tiên hoặc cuối cùng có vẻ quá mức cần thiết trong bất kỳ ngôn ngữ hoặc khuôn khổ nào.

+0

Các phương pháp lấy chìa khóa trong LINQ không may trả lại tối đa/tối thiểu chính nó chứ không phải là đối tượng chứa khóa đó. –

+0

bạn không thể tạo khóa được sáng tác sau đó? Trong python nó rất điển hình để sắp xếp một tuple tạm thời có chứa khóa và toàn bộ bản ghi, vì chúng được so sánh theo từ điển. – fortran

+1

Mặc dù .NET 4.0 có kiểu Tuple, .NET 3.5 không. Có thể là cách tiếp cận này sẽ làm việc trong .NET 4.0, nhưng tôi không chắc nó rất thành ngữ. –

2

Đây có phải là trong SQL hoặc LINQ to Objects không? Nếu sau này, bạn có thể muốn MinBy từ MoreLINQ; tuyên bố của bạn bằng văn bản sẽ thực sự sắp xếp và sau đó lấy mục đầu tiên.

Và có, đó là một sự xấu hổ rằng nó không bao gồm này (và những thứ tương tự như DistinctBy) ra khỏi hộp.

EDIT: Tôi thấy câu hỏi của bạn đã thay đổi; MoreLINQ không hỗ trợ so sánh hợp chất như vậy. Trong MiscUtil Tôi có mã để tạo hợp chất IComparer<T> - bạn có thể chuyển số đó vào MinBy bằng cách sử dụng chức năng nhận dạng làm công cụ chọn khóa. Cảm thấy tự do để thêm một yêu cầu tính năng cho một MinBy mà phải mất một nguồn và một IComparer<T> mà không có một selector chìa khóa :)

+0

Cảm ơn, tôi sẽ xem xét những điều này. Thật sự đáng tiếc khi không có cách nào để chuyển đổi giữa các tập hợp các biểu thức chính (ví dụ như được sử dụng với OrderBy ... ThenBy) và một IComparer. – Avish

+1

Một thay thế cho 'ThenBy' có thể trả về một bộ tuple:' Tuple.Create (post.PublishData, post.CommentsCount) '. –

Các vấn đề liên quan