我有一个List,MyStuff有一个Type Float属性。
有些属性值为10,20,22,30的对象。
我需要编写一个查找最接近21的对象的查询,在这种情况下,它会找到20和22对象。然后我需要编写一个发现对象接近21而不会过去的东西,它会返回值为20的对象。
我不知道在哪里/如何开始这个。帮助
感谢。
更新 - 哇这里有很多很棒的回复。谢谢!我不知道应该遵循哪一个,所以我会尝试一下。有一点可能使这个更多(或更少)有趣的是同一个查询将必须应用于LINQ-to-SQL实体,所以从MS Linq论坛收集的答案可能会发挥最佳作用?不知道。
答案 0 :(得分:24)
尝试按数字和21之差的绝对值对它们进行排序,然后取第一项:
float closest = MyStuff
.Select (n => new { n, distance = Math.Abs (n - 21) })
.OrderBy (p => p.distance)
.First().n;
根据@Yuriy Faktorovich的评论缩短它:
float closest = MyStuff
.OrderBy(n => Math.Abs(n - 21))
.First();
答案 1 :(得分:20)
这是一个满足线性时间内第二个查询的解决方案:
var pivot = 21f;
var closestBelow = pivot - numbers.Where(n => n <= pivot)
.Min(n => pivot - n);
(澄清后从“上方”编辑到“下方”)
对于第一个查询,最简单的方法是使用MoreLinq
的MinBy
扩展名:
var closest = numbers.MinBy(n => Math.Abs(pivot - n));
也可以在标准LINQ中以线性时间进行,但是有2次传递:
var minDistance = numbers.Min(n => Math.Abs(pivot - n));
var closest = numbers.First(n => Math.Abs(pivot - n) == minDistance);
如果效率不是问题,您可以对序列进行排序,并选择其他人发布的O(n * log n)
中的第一个值。
答案 2 :(得分:7)
基于Microsoft Linq论坛的this post:
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 );
答案 3 :(得分:3)
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();
这里有一个扩展方法:
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();
}
用法:
var result = numbers.Closest(n => n, pivot);