Reputation: 4626
Suppose I have a list of items (e.g., Posts) and I want to find the first item according to some non-trivial ordering (e.g., PublishDate and then CommentsCount as a tie-breaker). The natural way to do this with LINQ is like this:
posts.OrderBy(post => post.PublishDate).ThenBy(post => post.CommentsCount).First()
However, the micro-optimizer in me is worried that calling OrderBy actually costs me O(n*lgn) for sorting the entire list, when all I really need is an O(n) find-minimum operation.
So, is LINQ smart enough to return something from OrderBy() that knows how to optimize subsequent First() calls? If not, what's a better way to do this out-of-the-box? (I can always write my own FindMinimumItem implementation but that seems like overkill).
Upvotes: 8
Views: 372
Reputation: 700562
The sorting is smart in the way that it will only do the ThenBy
on the first group from the OrderBy
, but the OrderBy
still has to sort all items before it can return the first group.
You can use the Aggregate method to get the first post according to a custom comparison:
Post lowest =
posts.Aggregate((Post)null,
(x, y) =>
x == null
|| y.PublishDate < x.PublishDate
|| (y.PublishDate == x.PublishDate && y.CommentsCount < x.CommentsCount)
? y : x
);
(Assuming that you are using LINQ to Objects of course.)
Upvotes: 2
Reputation: 1502106
Is this in SQL or LINQ to Objects? If it's the latter, you probably want MinBy
from MoreLINQ; your statement as written will indeed sort and then take the first item.
And yes, it's a shame that it doesn't include this (and similar things like DistinctBy
) out of the box.
EDIT: I see your question has now changed; MoreLINQ doesn't support a compound comparison like that. In MiscUtil I have code to create a compound IComparer<T>
- you could pass that into MinBy
using the identity function as the key selector. Feel free to add a feature request for a MinBy
which takes a source and an IComparer<T>
without a key selector :)
Upvotes: 2
Reputation: 76077
Usually that is a max
or min
(I don't know the how is it called in LinQ), given a specific key; sorting and getting the first or last seems overkill in any language or framework.
Upvotes: 0