LINQ获得最接近的价值?

时间:2010-09-16 02:34:19

标签: c# linq listview object

我有一个List,MyStuff有一个Type Float属性。

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

我需要编写一个查找最接近21的对象的查询,在这种情况下,它会找到20和22对象。然后我需要编写一个发现对象接近21而不会过去的东西,它会返回值为20的对象。

我不知道在哪里/如何开始这个。帮助

感谢。

更新 - 哇这里有很多很棒的回复。谢谢!我不知道应该遵循哪一个,所以我会尝试一下。有一点可能使这个更多(或更少)有趣的是同一个查询将必须应用于LINQ-to-SQL实体,所以从MS Linq论坛收集的答案可能会发挥最佳作用?不知道。

4 个答案:

答案 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);

(澄清后从“上方”编辑到“下方”)

对于第一个查询,最简单的方法是使用MoreLinqMinBy扩展名:

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