开发者

How to find the first item according to a specific ordering using LINQ in O(n)?

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.Publ开发者_StackOverflow社区ishDate).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).


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


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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜