我有一个List,MyStuff有一个Float类型的属性。
有属性值为 10,20,22,30 的对象。
我需要编写一个查询来查找最接近 21 的对象,在本例中它将找到 20 和 22 对象。然后我需要写一个找到接近 21 的对象而不超过,它会返回值为 20 的对象。
我不知道从哪里/如何开始这个。帮忙吗?
谢谢。
更新 - 哇这里有这么多很棒的回复。谢谢!我不知道该遵循哪一个,所以我会尝试所有的。可能使这变得更(或更少)有趣的是,相同的查询必须适用于 LINQ-to-SQL 实体,因此从 MS Linq 论坛获得的答案可能效果最好?不知道。
尝试按数字与 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();
这里有一个在线性时间内满足第二个查询的解决方案:
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)
中的第一个值,正如其他人发布的那样。
基于 Microsoft Linq 论坛上的 这篇文章:
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 );
List<float> numbers = new List<float>() { 10f, 20f, 22f, 30f };
float pivot = 21f;
var result = numbers.Where(x => x >= pivot).OrderBy(x => x).FirstOrDefault();
或
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);
自 .net 6 起,可以使用 MinBy 来以与最受支持的帖子中类似的方式实现结果。它现在是标准 Linq 的一部分。 用途:
float closest = MyStuff.MinBy(x => Math.Abs(x - 21));