LINQ获得最接近的价值?

Sno*_*owy 32 c# linq listview object

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

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

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

我不知道在哪里/如何开始这个.救命?

谢谢.

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

amu*_*rra 24

尝试按数字和21之间的差值的绝对值对它们进行排序,然后取第一项:

float closest = MyStuff
    .Select (n => new { n, distance = Math.Abs (n - 21) })
    .OrderBy (p => p.distance)
    .First().n;
Run Code Online (Sandbox Code Playgroud)

或根据@Yuriy Faktorovich的评论缩短它:

float closest = MyStuff
    .OrderBy(n => Math.Abs(n - 21))
    .First();
Run Code Online (Sandbox Code Playgroud)

  • 您可以通过删除"Select"并将距离放入"OrderBy"来缩短它 (7认同)

Ani*_*Ani 22

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

var pivot = 21f;
var closestBelow = pivot - numbers.Where(n => n <= pivot)
                                  .Min(n => pivot - n);
Run Code Online (Sandbox Code Playgroud)

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

至于第一个查询,这将是最容易使用MoreLinqMinBy扩展:

var closest = numbers.MinBy(n => Math.Abs(pivot - n));
Run Code Online (Sandbox Code Playgroud)

它也可以在标准LINQ中以线性时间进行,但是有2次传递:

var minDistance = numbers.Min(n => Math.Abs(pivot - n));
var closest = numbers.First(n => Math.Abs(pivot - n) == minDistance);
Run Code Online (Sandbox Code Playgroud)

如果效率不是问题,您可以对序列进行排序并选择O(n * log n)其他人发布的第一个值.


nrk*_*rkn 7

基于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 );
Run Code Online (Sandbox Code Playgroud)