web-dev-qa-db-fra.com

C # recherche la valeur la plus proche dans un tableau

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

int TargetNumber = 13;

Pour un nombre cible, je veux trouver le nombre le plus proche dans un tableau. Par exemple, lorsque le nombre cible est 13, le nombre le plus proche dans le tableau ci-dessus est 15. Comment pourrais-je accomplir cela par programme en C #?

25
user1328639

Si vous utilisez .Net 3.5 ou supérieur, LINQ peut vous aider ici:

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

Alternativement, vous pouvez écrire votre propre méthode d'extension:

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

Utilisable comme tel:

var closest = array.ClosestTo(targetNumber);
26
Rich O'Kelly

Jon et Rich ont tous deux donné d'excellentes réponses avec MinBy et ClosestTo. Mais je ne recommanderais jamais d'utiliser OrderBy si votre intention est de trouver un seul élément. C'est beaucoup trop inefficace pour ce genre de tâches. C'est simplement le mauvais outil pour le travail.

Voici une technique qui fonctionne légèrement mieux que MinBy, est déjà incluse dans le framework .NET mais moins élégante que MinBy: Aggregate

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

Comme je l'ai dit, pas aussi élégante que la méthode de Jon, mais viable.

Performance sur mon ordinateur:

  1. Pour (chaque) Boucles = le plus rapide
  2. Agrégat = 2,5 fois plus lent que les boucles
  3. MinBy = 3,5x plus lent que les boucles
  4. OrderBy = 12x plus lent que les boucles
13
Lee Grissom

J'ai trouvé cette approche très sexy il y a des années dans Math.NET Numerics https://numerics.mathdotnet.com/ qui fonctionne avec BinarySearch dans le tableau. Ce fut une bonne aide pour la préparation des interpolations et passe à .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);
}
2
NilesDavis

Le code personnalisé sage de performance sera plus utile. 

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;
}
1
Amit Srivastava

Si vous avez besoin de trouver la valeur la plus proche de la moyenne

style très ouvert

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;
    }
}
0
Samuel Lehikoinen