LINQ 获取最接近的值?

问题描述 投票:0回答:5

我有一个List,MyStuff有一个Float类型的属性。

有属性值为 10,20,22,30 的对象。

我需要编写一个查询来查找最接近 21 的对象,在本例中它将找到 20 和 22 对象。然后我需要写一个找到接近 21 的对象而不超过,它会返回值为 20 的对象。

我不知道从哪里/如何开始这个。帮忙吗?

谢谢。

更新 - 哇这里有这么多很棒的回复。谢谢!我不知道该遵循哪一个,所以我会尝试所有的。可能使这变得更(或更少)有趣的是,相同的查询必须适用于 LINQ-to-SQL 实体,因此从 MS Linq 论坛获得的答案可能效果最好?不知道。

c# linq listview object
5个回答
35
投票

尝试按数字与 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();

26
投票

这里有一个在线性时间内满足第二个查询的解决方案:

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)
中的第一个值,正如其他人发布的那样。


10
投票

基于 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 );

4
投票
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);

0
投票

自 .net 6 起,可以使用 MinBy 来以与最受支持的帖子中类似的方式实现结果。它现在是标准 Linq 的一部分。 用途:

float closest = MyStuff.MinBy(x => Math.Abs(x - 21));
© www.soinside.com 2019 - 2024. All rights reserved.