Подтвердить что ты не робот

LINQ, чтобы получить самое близкое значение?

У меня есть List, MyStuff имеет свойство Type Float.

Существуют объекты со значениями свойств 10,20,22,30.

Мне нужно написать запрос, который найдет объекты, наиболее близкие к 21, в этом случае он найдет объект 20 и 22. Затем мне нужно написать тот, который обнаруживает, что объект закрывается до 21, не перейдя, и он вернет объект со значением 20.

Я понятия не имею, где и как начать с этого. Помощь?

Спасибо.

Update - ничего страшного здесь. Благодарю! Я не знаю, за кем следовать, поэтому я попробую их всех. Одна вещь, которая может сделать это более (или менее) интересным, заключается в том, что тот же запрос должен применяться к объектам LINQ-to-SQL, поэтому, возможно, ответ, собранный с форумов MS Linq, будет работать лучше всего? Не знаю.

4b9b3361

Ответ 1

Здесь решение, удовлетворяющее второму запросу в линейном времени:

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

(Отредактировано от "выше" до "ниже" после уточнения)

Что касается первого запроса, было бы проще использовать MoreLinq MinBy extension:

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

Попробуйте отсортировать их по абсолютной величине разницы между числом и 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();

Ответ 3

На основе этот пост на форумах 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);