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

int TargetNumber = 13;

ターゲット番号については、配列内で最も近い番号を見つけたいと思います。たとえば、ターゲット番号が13の場合、上記の配列でそれに最も近い番号は15です。C#でプログラムでそれを達成するにはどうすればよいですか?

4

6 に答える 6

71

long編集:オーバーフローの問題を回避するために、以下のクエリを調整して算術演算を使用するように変換しました。

私はおそらくMoreLINQMinBy方法を使用するでしょう:

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

または、次を使用することもできます。

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

...しかし、それはあなたが本当に必要としないコレクション全体をソートします。確かに、小さな配列では大きな違いはありませんが、実際に何をしようとしているのかを説明するのと比べると、まったく正しく感じられません。関数に従って最小値の要素を見つけてください。

配列が空の場合、これらは両方とも失敗することに注意してください。最初にそれを確認する必要があります。

于 2012-04-12T09:32:37.217 に答える
31

If you're using .Net 3.5 or above LINQ can help you here:

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

Alternatively, you could write your own extension method:

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

Useable like so:

var closest = array.ClosestTo(targetNumber);
于 2012-04-12T09:32:46.110 に答える
21

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

私が言ったように、ジョンの方法ほどエレガントではありませんが、実行可能です。

私のコンピューターのパフォーマンス:

  1. For(each)ループ=最速
  2. 集計=ループより2.5倍遅い
  3. MinBy=ループより3.5倍遅い
  4. OrderBy=ループより12倍遅い
于 2012-12-15T22:21:38.450 に答える
4

数年前、配列内のBinarySearchで動作するMath.NETNumericshttps://numerics.mathdotnet.com/でこの本当にセクシーなアプローチを見つけました。これは、補間の準備に役立ち、.Net2.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);
}
于 2017-08-08T15:00:54.280 に答える
0

平均に最も近い値を見つける必要がある場合

とてもオープンなスタイル

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;
    }
}
于 2019-02-23T21:37:09.897 に答える
-1

パフォーマンスに関するカスタムコードの方が便利です。

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;
}
于 2014-01-07T07:38:51.423 に答える