LINQ, чтобы найти самое близкое число, которое больше/меньше входного

Предположим, что у меня есть список номеров:

List<int> = new List<int>(){3,5,8,11,12,13,14,21}

Предположим, что я хочу получить самое близкое число, которое меньше 11, это будет 8 Предположим, что я хочу получить самое близкое число, которое больше 13, что будет 14.

Цифры в списке не могут быть дублированы и всегда упорядочены. Как я могу написать Linq для этого?

Ответ 1

с Linq, предполагая, что список упорядочен, я бы сделал это следующим образом:

var l = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
var lessThan11 = l.TakeWhile(p => p < 11).Last();
var greaterThan13 = l.SkipWhile(p => p <= 13).First();

ИЗМЕНИТЬ:

Поскольку я получил отрицательные отзывы об этом ответе и ради людей, которые могут видеть этот ответ, и, хотя он принят, не идет дальше, я изучил другие комментарии относительно BinarySearch и решил добавить здесь второй вариант ( с некоторыми незначительными изменениями).

Это недостаточный способ, представленный где-то еще:

var l = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
var indexLessThan11 = ~l.BinarySearch(10) -1;
var value = l[indexLessThan11];

Теперь приведенный выше код не справляется с тем, что значение 10 действительно может быть в списке (в этом случае нельзя инвертировать индекс)! поэтому хороший способ это сделать:

var l = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
var indexLessThan11 = l.BinarySearch(10);
if (indexLessThan11 < 0) // the value 10 wasn't found
{    
    indexLessThan11 = ~indexLessThan11;
    indexLessThan11 -= 1;
}
var value = l[indexLessThan11];

Я просто хочу отметить, что:

l.BinarySearch(11) == 3
//and
l.BinarySearch(10) == -4;

Ответ 2

Использовать Array.BinarySearch - нет необходимости в LINQ или посещать в среднем половину элементов для поиска вашей цели.

Существует также множество классов SortedXXX, которые могут быть подходящими для того, что вы делаете [у которого будет такой эффективный поиск O (log N)]

Ответ 3

Вы можете сделать это, используя двоичный поиск. Если вы ищете 11, то, очевидно, вы получите индекс после. Если вы ищете 10 и используете побитовое дополнение к результату, вы получите самое близкое соответствие.

   List<int> list = new List<int>(){3,5,8,11,12,13,14,21};

   list.Sort();

   int index = list.BinarySearch(10);

   int found =  (~index)-1;

   Console.WriteLine (list[found]); // Outputs 8

То же самое происходит в другом направлении

int index = list.BinarySearch(15);

Console.WriteLine("Closest match : " + list[+~index]); // Outputs 21

Бинарные поиски также очень быстрые.

Ответ 4

ближайший номер ниже 11:

        int someNumber = 11;
        List<int> list = new List<int> { 3, 5, 8, 11, 12, 13, 14, 21 };

        var intermediate = from i in list
                     where i < someNumber
                     orderby i descending
                     select i;

        var result = intermediate.FirstOrDefault();

ближайший номер выше 13:

        int someNumber = 13;
        List<int> list = new List<int> { 3, 5, 8, 11, 12, 13, 14, 21 };

        var intermediate = from i in list
                     where i > someNumber
                     orderby i
                     select i;

        var result = intermediate.FirstOrDefault();

Ответ 5

Это мой ответ

List<int> myList = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
    int n = 11;
    int? smallerNumberCloseToInput = (from n1 in myList
                                    where n1 < n
                                    orderby n1 descending
                                    select n1).First();

    int? largerNumberCloseToInput = (from n1 in myList
                                    where n1 > n
                                    orderby n1 ascending
                                    select n1).First();

Ответ 6

Вы можете использовать запрос для этого, например:

List<int> numbers = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
List<int> output = (from n in numbers
                            where n > 13 // or whatever
                            orderby n ascending //or descending
                            select n).ToList();

Ответ 7

var list = new List<int> {14,2,13,11,5,8,21,12,3};
var tested = 11;

var closestGreater = list.OrderBy(n => n)
                         .FirstOrDefault(n => tested < n); // = 12

var closestLess = list.OrderByDescending(n => n)
                      .FirstOrDefault(n => tested > n); // = 8

if (closestGreater == 0)
    System.Diagnostics.Debug.WriteLine(
        string.Format("No number greater then {0} exists in the list", tested));

if (closestLess == 0)
    System.Diagnostics.Debug.WriteLine(
        string.Format("No number smaler then {0} exists in the list", tested));