I have a List, MyStuff has a property of Type Float.
There are objects with property values of 10,20,22,30.
I need to write a query that finds the objects cl
Try sorting them by the absolute value of the difference between the number and 21 and then take the first item:
float closest = MyStuff
.Select (n => new { n, distance = Math.Abs (n - 21) })
.OrderBy (p => p.distance)
.First().n;
Or shorten it according to @Yuriy Faktorovich's comment:
float closest = MyStuff
.OrderBy(n => Math.Abs(n - 21))
.First();
List<float> numbers = new List<float>() { 10f, 20f, 22f, 30f };
float pivot = 21f;
var result = numbers.Where(x => x >= pivot).OrderBy(x => x).FirstOrDefault();
OR
var result = (from n in numbers
where n>=pivot
orderby n
select n).FirstOrDefault();
and here comes an extension method:
public static T Closest<T,TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector, TKey pivot) where TKey : IComparable<TKey>
{
return source.Where(x => pivot.CompareTo(keySelector(x)) <= 0).OrderBy(keySelector).FirstOrDefault();
}
Usage:
var result = numbers.Closest(n => n, pivot);
Based on this post at the Microsoft Linq forums:
var numbers = new List<float> { 10f, 20f, 22f, 30f };
var target = 21f;
//gets single number which is closest
var closest = numbers.Select( n => new { n, distance = Math.Abs( n - target ) } )
.OrderBy( p => p.distance )
.First().n;
//get two closest
var take = 2;
var closests = numbers.Select( n => new { n, distance = Math.Abs( n - target ) } )
.OrderBy( p => p.distance )
.Select( p => p.n )
.Take( take );
//gets any that are within x of target
var within = 1;
var withins = numbers.Select( n => new { n, distance = Math.Abs( n - target ) } )
.Where( p => p.distance <= within )
.Select( p => p.n );
Here's a solution that satisfies the second query in linear time:
var pivot = 21f;
var closestBelow = pivot - numbers.Where(n => n <= pivot)
.Min(n => pivot - n);
(Edited from 'above' to 'below' after clarification)
As for the first query, it would be easiest to use MoreLinq's MinBy
extension:
var closest = numbers.MinBy(n => Math.Abs(pivot - n));
It's also possible to do it in standard LINQ in linear time, but with 2 passes of the source:
var minDistance = numbers.Min(n => Math.Abs(pivot - n));
var closest = numbers.First(n => Math.Abs(pivot - n) == minDistance);
If efficiency is not an issue, you could sort the sequence and pick the first value in O(n * log n)
as others have posted.