C # поиск ближайшего значения в массиве

<code>int[] array = new int[5]{5,7,8,15,20};

int TargetNumber = 13;
</code>

Для целевого числа я хочу найти ближайший номер в массиве. Например, когда целевое число равно 13, ближайший к нему в приведенном выше массиве равен 15. Как бы я достиг этого программным путем в C #?

Ответы на вопрос(6)

very open style
public static double Miidi(double[] list)
{
    bool isEmpty = !list.Any();
    if (isEmpty)
    {
        return 0;
    }
    else
    {
        double avg = list.Average();
        double closest = 100;
        double shortest = 100;
        {
            for ( int i = 0; i < list.Length; i++)
            {
                double lgth = list[i] - avg;
                if (lgth < 0)
                {
                    lgth = lgth - (2 * lgth);
                }
                else
                    lgth = list[i] - avg;

                if (lgth < shortest)
                {
                    shortest = lgth;
                    closest = list[i];
                }
            }
        }

        return closest;
    }
}

var closest = array.OrderBy(v => Math.Abs((long)v - targetNumber)).First();

Кроме того, вы можете написать свой собственный метод расширения:

public static int ClosestTo(this IEnumerable<int> collection, int target)
{
    // NB Method will return int.MaxValue for a sequence containing no elements.
    // Apply any defensive coding here as necessary.
    var closest = int.MaxValue;
    var minDifference = int.MaxValue;
    foreach (var element in collection)
    {
        var difference = Math.Abs((long)element - target);
        if (minDifference > difference)
        {
            minDifference = (int)difference;
            closest = element;
        }
    }

    return closest;
}

Можно использовать так:

var closest = array.ClosestTo(targetNumber);
 12 апр. 2012 г., 11:36
Стоит упомянуть, что это будет работать с .NET 4.0+, если у меня будет меньше, может быть, простой метод расширения тоже подойдет.
 12 апр. 2012 г., 11:48
@Tigran Методы OrderBy и First LINQ доступны с .Net 3.5. Однако я понимаю вашу точку зрения, ответ обновлен.
 12 апр. 2012 г., 11:55
также, если у вас есть массив с{5,7,8,15,20} а такжеtargetNumber = 6ближайший будет 5; если массив{7,5,8,15,20} ближайший будет 7
 12 апр. 2012 г., 11:51
+1 за это. Но я использую 3.5 и не имею этой функции. Так что лучше иметь "B" вариант.
 12 апр. 2012 г., 12:14
@Tigran:Which у вас нет функции? Если вы используете .NET 3.5, у вас наверняка есть OrderBy и First - хотя вам потребуется директива using для System.Linq.

public static int FindNearest(int targetNumber, IEnumerable<int> collection) {
    var results = collection.ToArray();
    int nearestValue;
    if (results.Any(ab => ab == targetNumber))
        nearestValue = results.FirstOrDefault(i => i == targetNumber);
    else{
        int greaterThanTarget = 0;
        int lessThanTarget = 0;
        if (results.Any(ab => ab > targetNumber)) {
            greaterThanTarget = results.Where(i => i > targetNumber).Min();
        }
        if (results.Any(ab => ab < targetNumber)) {
            lessThanTarget = results.Where(i => i < targetNumber).Max();
        }

        if (lessThanTarget == 0) {
            nearestValue = greaterThanTarget;
        }
        else if (greaterThanTarget == 0) {
            nearestValue = lessThanTarget;
        }
        else if (targetNumber - lessThanTarget < greaterThanTarget - targetNumber) {
            nearestValue = lessThanTarget;
        }
        else {
            nearestValue = greaterThanTarget;
        }
    }
    return nearestValue;
}
Решение Вопроса

скорректировать запросы ниже, чтобы преобразовать в использованиеlong арифметика, чтобы избежать проблем переполнения.

Я бы наверное использовалMoreLINQ& APOS; sMinBy метод:

var nearest = array.MinBy(x => Math.Abs((long) x - targetNumber));

Или тыcould просто используйте:

var nearest = array.OrderBy(x => Math.Abs((long) x - targetNumber)).First();

... но это отсортирует всю коллекцию, которая вам действительно не нужна. Это не будет иметь большого значения дляsmall массив, по общему признанию ... но это просто не совсем правильно, по сравнению с описанием того, что выactually пытаясь сделать: найти элемент с минимальным значением согласно какой-либо функции.

Обратите внимание, что оба из них потерпят неудачу, если массив пуст, поэтому вам следует сначала проверить это.

 14 авг. 2013 г., 13:36
@JonSkeet Есть ли способ изменить версию MinBy, чтобы она возвращала индекс вместо значения?
 14 июл. 2017 г., 09:26
@rraszewski: тогдаif массив потенциально большой, я, вероятно, использовал бы бинарный поиск, предполагая, что входной массив фактически отсортирован для начала. Это требует больше кода, но будет более эффективным.
 14 авг. 2013 г., 14:20
@ManInMoon: самый простой подход будет использоватьSelect((value, index) => new { Value, Index }) для начала, тоMinBy вернет пару, содержащую минимальное значение, и вы можете получить индекс таким образом.
 14 июл. 2017 г., 09:23
Что делать, если я хочу найти ближайший номер не только один раз, но несколько раз. Это что-то меняет? И я не хочу звонитьOrderBy для каждого номера, который я хочу найти.

MinBy а такжеClosestTo, Но я бы никогда не рекомендовал использоватьOrderBy если ваше намерение состоит в том, чтобы найти один элемент. Это слишком неэффективно для таких задач. Это просто неподходящий инструмент для работы.

Вот методика, которая работает немного лучше, чем MinBy, уже включена в .NET Framework, но менее элегантна, чем MinBy:Aggregate

var nearest = array.Aggregate((current, next) => Math.Abs((long)current - targetNumber) < Math.Abs((long)next - targetNumber) ? current : next);

Как я уже сказал, не такой элегантный, как метод Джона, но жизнеспособный.

Производительность на моем компьютере:

For(each) Loops = fastest Aggregate = 2.5x slower than loops MinBy = 3.5x slower than loops OrderBy = 12x slower than loops

ET Numericshttps://numerics.mathdotnet.com/ который работает с BinarySearch в массиве. Это было хорошим подспорьем в подготовке к интерполяции и работало до .Net 2.0:

public static int LeftSegmentIndex(double[] array, double t)
{
    int index = Array.BinarySearch(array, t);
    if (index < 0)
    {
        index = ~index - 1;
    }
    return Math.Min(Math.Max(index, 0), array.Length - 2);
}

Ваш ответ на вопрос