LINQ to Get Closest Value?

前端 未结 4 517
独厮守ぢ
独厮守ぢ 2020-12-13 06:20

I have a List, MyStuff has a property of Type Float.

There are objects with property values of 10,20,22,30.

I need to write a query that finds the objects cl

相关标签:
4条回答
  • 2020-12-13 06:46

    Try sorting them by the absolute value of the difference between the number and 21 and then take the first item:

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

    Or shorten it according to @Yuriy Faktorovich's comment:

    float closest = MyStuff
        .OrderBy(n => Math.Abs(n - 21))
        .First();
    
    0 讨论(0)
  • 2020-12-13 06:46
    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();
    

    and here comes an extension method:

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

    Usage:

    var result = numbers.Closest(n => n, pivot);
    
    0 讨论(0)
  • 2020-12-13 06:56

    Based on this post at the Microsoft Linq forums:

    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 );
    
    0 讨论(0)
  • 2020-12-13 07:07

    Here's a solution that satisfies the second query in linear time:

    var pivot = 21f;
    var closestBelow = pivot - numbers.Where(n => n <= pivot)
                                      .Min(n => pivot - n);
    

    (Edited from 'above' to 'below' after clarification)

    As for the first query, it would be easiest to use MoreLinq's MinBy extension:

    var closest = numbers.MinBy(n => Math.Abs(pivot - n));
    

    It's also possible to do it in standard LINQ in linear time, but with 2 passes of the source:

    var minDistance = numbers.Min(n => Math.Abs(pivot - n));
    var closest = numbers.First(n => Math.Abs(pivot - n) == minDistance);
    

    If efficiency is not an issue, you could sort the sequence and pick the first value in O(n * log n) as others have posted.

    0 讨论(0)
提交回复
热议问题