开发者

How to use linq to find the minimum [duplicate]

开发者 https://www.devze.com 2022-12-28 09:04 出处:网络
This question already has answers here: How to use LINQ to select object with minimum or maximum property value
This question already has answers here: How to use LINQ to select object with minimum or maximum property value 开发者_运维百科 (20 answers) Closed 8 years ago.

I have a class A { public float Score; ... } and an IEnumerable<A> items and would like to find the A which has minimal score.

Using items.Min(x => x.Score) gives the minimal score and not the instance with minimal score.

How can I get the instance by iterating only once through my data?

Edit: So long there are three main solutions:

  • Writing an extension method (proposed by Svish). Pros: Easy to use and evaluates Score only once per item. Cons: Needs an extension method. (I choosed this solution for my application.)

  • Using Aggregate (proposed by Daniel Renshaw). Pros: Uses a built-in LINQ method. Cons: Slightly obfuscated to the untrained eye and calls evaluator more than once.

  • Implementing IComparable (proposed by cyberzed). Pros: Can use Linq.Min directly. Cons: Fixed to one comparer - can not freely choose comparer when performing the minimum computation.


Use Aggregate:

items.Aggregate((c, d) => c.Score < d.Score ? c : d)

As suggested, exact same line with more friendly names:

items.Aggregate((minItem, nextItem) => minItem.Score < nextItem.Score ? minItem : nextItem)


Try items.OrderBy(s => s.Score).FirstOrDefault();


Have a look at the MinBy extension method in MoreLINQ (created by Jon Skeet, now principally maintained by Atif Aziz).

  • MinBy documentation

  • MinBy source code (it's pretty straightforward and has no dependencies on other files).


This can be solved with a little simple iteration:

float minScore = float.MaxValue;
A minItem = null;

foreach(A item in items)
{
   if(item.Score < minScore)
       minItem = item;
}

return minItem;

It's not a nice LINQ query, but it does avoid a sorting operation and only iterates the list once, as per the question's requirements.


The quick way as I see it would be implementing IComparable for your class A (if possible ofcourse)

class A : IComparable<A>

It's a simple implementation where you write the CompareTo(A other) have a look at IEnumerable(of T).Min on MSDN for a reference guide


A little fold should do:

var minItem = items.Aggregate((acc, c) => acc.Score < c.Score? acc : c);

Ah... too slow.


Jamie Penney got my vote. You can also say

items.OrderBy(s => s.Score).Take(1);

Which has the same effect. Use Take(5) to take the lowest 5 etc.

0

精彩评论

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