Return the best matching item from the collection in C # 3.5 in just a row or two

Here is an example of code that I basically wrote thousands of times in my life:

// find bestest thingy Thing bestThing; float bestGoodness = FLOAT_MIN; foreach( Thing x in arrayOfThings ) { float goodness = somefunction( x.property, localvariable ); if( goodness > bestGoodness ) { bestGoodness = goodness; bestThing = x; } } return bestThing; 

And it seems to me that C # should have something that does this in only one line. Something like:

 return arrayOfThings.Max( delegate(x) { return somefunction( x.property, localvariable ); }); 

But this does not return a thing (or an index for a thing that will be in order) that returns a Q value.

So it could be something like:

 var sortedByGoodness = from x in arrayOfThings orderby somefunction( x.property, localvariable ) ascending select x; return x.first; 

But this makes the whole look of the whole array and can be too slow.

Does it exist?

+8
c # max linq
source share
4 answers

I don't think this is possible in standard LINQ without sorting enuermable (which is slow in the general case), but you can use the MaxBy() method from the MoreLinq library to achieve this. I always include this library in my projects, as it is so useful.

http://code.google.com/p/morelinq/source/browse/trunk/MoreLinq/MaxBy.cs

(The code is really very similar to what you have, but generalized.)

+2
source share

This is what you can do using System.Linq:

 var value = arrayOfThings .OrderByDescending(x => somefunction(x.property, localvariable)) .First(); 

If the array may be empty, use .FirstOrDefault(); to avoid exceptions.

You really don't know how this is implemented internally, so you cannot guarantee that it will sort the entire array to get the first element. For example, if it was linq for sql, the server would receive a request including sorting and condition. It will not receive the array, then it will sort it, and then will receive the first element.

In fact, until you call First, the first part of the request will not be evaluated. I mean, this is not a two-step assessment, but a one-step assessment.

 var sortedValues =arrayOfThings .OrderByDescending(x => somefunction(x.property, localvariable)); // values isn't still evaluated var value = sortedvalues.First(); // the whole expression is evaluated at this point. 
+3
source share

I would do IComparable<Thing> and just use arrayOfThings.Max() .

Example here: http://msdn.microsoft.com/en-us/library/bb347632.aspx

I think this is the cleanest approach, and IComparable might be useful elsewhere.

UPDATE

There is also an overloaded Max method that performs the projection function, so you can provide different logic for getting height, age, etc.

http://msdn.microsoft.com/en-us/library/bb534962.aspx

+1
source share

I followed the Porges link in the comment How to use LINQ to select an object with the minimum or maximum value of the property and executed the following code in LINQPad and confirmed that both LINQ expressions returned the correct answers.

 void Main() { var things = new Thing [] { new Thing { Value = 100 }, new Thing { Value = 22 }, new Thing { Value = 10 }, new Thing { Value = 303 }, new Thing { Value = 223} }; var query1 = (from t in things orderby GetGoodness(t) descending select t).First(); var query2 = things.Aggregate((curMax, x) => (curMax == null || (GetGoodness(x) > GetGoodness(curMax)) ? x : curMax)); } int GetGoodness(Thing thing) { return thing.Value * 2; } public class Thing { public int Value {get; set;} } 


Result from LinqPad

Results from LinqPad

0
source share

All Articles