C#は最高の配列値とインデックスを見つけます


89

だから私はソートされていない数値配列を持っていてint[] anArray = { 1, 5, 2, 7 };、値と7と3になる配列の最大値のインデックスの両方を取得する必要がありますか?


これまでのところMax()メソッドを使用してから、バイナリ検索メソッドを使用してその最大値のインデックスを取得しようとしましたが、配列がソートされていないので機能しません。
Edmund Rojas

@EdmundRojasバイナリ検索を使用する必要はありません。単純な旧式の線形検索は、並べ替えられていないリストに対しては正常に機能します。
millimoose

回答:


138

これは最も魅力的な方法ではありませんが、機能します。

(持っている必要がありますusing System.Linq;

 int maxValue = anArray.Max();
 int maxIndex = anArray.ToList().IndexOf(maxValue);

10
コーディング時間を大幅に節約できますが、コレクションを2回実行することになります。
Garo Yeriazarian

11
.ToList()配列も明示的に実装する必要はありませんIList
millimoose

@GaroYeriazarianユースケースにとって線形の複雑さが多すぎる場合は、定数係数を3分の1に減らすだけでなく、それ以上の削減が必要になる可能性があります。(もちろん、無視できるほどの最適化ではありません。)
millimoose

1
@ sa_ddam213配列は、 IListインターフェイスをますが、明示的にます:msdn.microsoft.com/en-us/library/…。(配列には、対応する汎用IList<T>インターフェイスも実装されています。)
millimoose

1
@ sa_ddam213いいえ、契約ToList()は常にコピーすることです。メソッドをコピーすることもコピーしないことも、ひどい考えです。これは、かなりクレイジーなエイリアシングバグにつながります。実際の実装はToList()多かれ少なかれreturn new List(source)
ミリムース

42
int[] anArray = { 1, 5, 2, 7 };
// Finding max
int m = anArray.Max();

// Positioning max
int p = Array.IndexOf(anArray, m);

28

インデックスがソートされていない場合は、少なくとも1回配列を反復処理して、最大値を見つける必要があります。シンプルなforループをます。

int? maxVal = null; //nullable so this works even if you have all super-low negatives
int index = -1;
for (int i = 0; i < anArray.Length; i++)
{
  int thisNum = anArray[i];
  if (!maxVal.HasValue || thisNum > maxVal.Value)
  {
    maxVal = thisNum;
    index = i;
  }
}

これは、LINQや他の1行のソリューションを使用するものよりも詳細ですが、おそらく少し高速です。これをO(N)より速くする方法は本当にありません。


4
maxValインデックス0の配列値に初期化し(配列の長さが1であると想定)、0に初期化してindex、forループをで開始することにより、1回の反復を保存できますi = 1
Jon Schneider

13

必須のLINQ one [1]-ライナー:

var max = anArray.Select((value, index) => new {value, index})
                 .OrderByDescending(vi => vi.value)
                 .First();

(ソートはおそらく他のソリューションよりもパフォーマンスに影響を与えます。)

[1]:与えられた値「1」の場合。


14
このソリューションを追加するのは、せいぜいO(nlogn)の複雑さです。ソートされていない配列の場合、最大値の検索はO(n)時間で取得できます。
dopplesoldner 2014年

13

簡潔なワンライナー:

var max = anArray.Select((n, i) => (Number: n, Index: i)).Max();

テストケース:

var anArray = new int[] { 1, 5, 2, 7 };
var max = anArray.Select((n, i) => (Number: n, Index: i)).Max();
Console.WriteLine($"Maximum number = {max.Number}, on index {max.Index}.");
// Maximum number = 7, on index 4.

特徴:

  • Linqを使用します(バニラほど最適化されていませんが、トレードオフはより少ないコードです)。
  • ソートする必要はありません。
  • 計算の複雑さ:O(n)。
  • スペースの複雑さ:O(n)。

備考:

  • タプルのソートはタプルの項目を左から右に比較することで行われるため、番号(インデックスではなく)がタプルの最初の要素であることを確認してください。

これは本当にすてきです!
フロイドホールド

これが機能するためには、マックスバイされるアイテムが最初でなければならないことを指摘しておく必要あります
Caius Jard

@CaiusJardはどういう意味ですか?テストケースに示されているように、最大​​の項目が正しく検出され最後の項目でした。
Lesair Valmont

たとえば、タプルの最初で、タプルのanArray.Select((n, i) => ( Index: i, Number: n)).Max()比較方法のために、最大数ではなく最大インデックスを見つけます(item1が最も重要など)
Caius

十分に公正な@CaiusJard、私はそれを指摘するためにコメントを追加しました。ありがとう。
Lesair Valmont

3

ここに2つのアプローチがあります。配列が空の場合の処理​​を追加することもできます。

public static void FindMax()
{
    // Advantages: 
    // * Functional approach
    // * Compact code
    // Cons: 
    // * We are indexing into the array twice at each step
    // * The Range and IEnumerable add a bit of overhead
    // * Many people will find this code harder to understand

    int[] array = { 1, 5, 2, 7 };

    int maxIndex = Enumerable.Range(0, array.Length).Aggregate((max, i) => array[max] > array[i] ? max : i);
    int maxInt = array[maxIndex];

    Console.WriteLine($"Maximum int {maxInt} is found at index {maxIndex}");
}

public static void FindMax2()
{
    // Advantages: 
    // * Near-optimal performance

    int[] array = { 1, 5, 2, 7 };
    int maxIndex = -1;
    int maxInt = Int32.MinValue;

    // Modern C# compilers optimize the case where we put array.Length in the condition
    for (int i = 0; i < array.Length; i++)
    {
        int value = array[i];
        if (value > maxInt)
        {
            maxInt = value;
            maxIndex = i;
        }
    }

    Console.WriteLine($"Maximum int {maxInt} is found at index {maxIndex}");
}

1
anArray.Select((n, i) => new { Value = n, Index = i })
    .Where(s => s.Value == anArray.Max());

すべての反復でanArray.Max()を計算しているため、これはO(n ^ 2)ソリューションです。大きな配列の場合は非常に遅くなります。
Neil、

1
int[] numbers = new int[7]{45,67,23,45,19,85,64}; 
int smallest = numbers[0]; 
for (int index = 0; index < numbers.Length; index++) 
{ 
 if (numbers[index] < smallest) smallest = numbers[index]; 
} 
Console.WriteLine(smallest);

1

以下のコードの出力:

00:00:00.3279270-max1 00:00:00.2615935-max2 00:00:00.6010360-max3(arr.Max())

配列の100000000 intの場合、それほど大きな違いはありませんが、それでも...

class Program
    {
        static void Main(string[] args)
        {
            int[] arr = new int[100000000];

            Random randNum = new Random();
            for (int i = 0; i < arr.Length; i++)
            {
                arr[i] = randNum.Next(-100000000, 100000000);
            }
            Stopwatch stopwatch1 = new Stopwatch();
            Stopwatch stopwatch2 = new Stopwatch();
            Stopwatch stopwatch3 = new Stopwatch();
            stopwatch1.Start();

            var max = GetMaxFullIterate(arr);

            Debug.WriteLine( stopwatch1.Elapsed.ToString());


            stopwatch2.Start();
            var max2 = GetMaxPartialIterate(arr);

            Debug.WriteLine( stopwatch2.Elapsed.ToString());

            stopwatch3.Start();
            var max3 = arr.Max();
            Debug.WriteLine(stopwatch3.Elapsed.ToString());

        }



 private static int GetMaxPartialIterate(int[] arr)
        {
            var max = arr[0];
            var idx = 0;
            for (int i = arr.Length / 2; i < arr.Length; i++)
            {
                if (arr[i] > max)
                {
                    max = arr[i];
                }

                if (arr[idx] > max)
                {
                    max = arr[idx];
                }
                idx++;
            }
            return max;
        }


        private static int GetMaxFullIterate(int[] arr)
        {
            var max = arr[0];
            for (int i = 0; i < arr.Length; i++)
            {
                if (arr[i] > max)
                {
                    max = arr[i];
                }
            }
            return max;
        }

1
 public static class ArrayExtensions
{
    public static int MaxIndexOf<T>(this T[] input)
    {
        var max = input.Max();
        int index = Array.IndexOf(input, max);
        return index;
    }
}

これはすべての変数タイプで機能します...

var array = new int[]{1, 2, 4, 10, 0, 2};
var index = array.MaxIndexOf();


var array = new double[]{1.0, 2.0, 4.0, 10.0, 0.0, 2.0};
var index = array.MaxIndexOf();

1
public static void Main()
{
    int a,b=0;
    int []arr={1, 2, 2, 3, 3, 4, 5, 6, 5, 7, 7, 7, 100, 8, 1};

    for(int i=arr.Length-1 ; i>-1 ; i--)
        {
            a = arr[i];

            if(a > b)
            {
                b=a;    
            }
        }
    Console.WriteLine(b);
}

0
int[] Data= { 1, 212, 333,2,12,3311,122,23 };
int large = Data.Max();
Console.WriteLine(large);

1
あなたの答えは最高値のみを示しますが、質問者は最高値と最高値のインデックスの両方を要求しました。
Cardin

0

以下は、適切な定数係数を持つO(n)であるLINQソリューションです。

int[] anArray = { 1, 5, 2, 7, 1 };

int index = 0;
int maxIndex = 0;

var max = anArray.Aggregate(
    (oldMax, element) => {
        ++index;
        if (element <= oldMax)
            return oldMax;
        maxIndex = index;
        return element;
    }
);

Console.WriteLine("max = {0}, maxIndex = {1}", max, maxIndex);

ただしfor、パフォーマンスを重視する場合は、明示的なlop を実際に作成する必要があります。


0

を使用してちょうど別の視点DataTable。andとDataTable呼ばれる2つの列を持つa を宣言します。オプションとその両方および値を列に追加します。次に、ループを使用して、各配列項目を行として挿入します。次に、メソッドを使用して、最大値を持つ行を選択します。indexvalAutoIncrementAutoIncrementSeedAutoIncrementStep1indexforeachdatatableSelect

コード

int[] anArray = { 1, 5, 2, 7 };
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[2] { new DataColumn("index"), new DataColumn("val")});
dt.Columns["index"].AutoIncrement = true;
dt.Columns["index"].AutoIncrementSeed = 1;
dt.Columns["index"].AutoIncrementStep = 1;
foreach(int i in anArray)
    dt.Rows.Add(null, i);

DataRow[] dr = dt.Select("[val] = MAX([val])");
Console.WriteLine("Max Value = {0}, Index = {1}", dr[0][1], dr[0][0]);

出力

Max Value = 7, Index = 4

ここでデモを探す


0

配列内の最大数と最小数を見つけます。

int[] arr = new int[] {35,28,20,89,63,45,12};
int big = 0;
int little = 0;

for (int i = 0; i < arr.Length; i++)
{
    Console.WriteLine(arr[i]);

    if (arr[i] > arr[0])
    {
        big = arr[i];
    }
    else
    {
        little = arr[i];

    }
}

Console.WriteLine("most big number inside of array is " + big);
Console.WriteLine("most little number inside of array is " + little);

1
最小値/最大値ではなく、配列の最初の値よりも大きい/小さい最後の値を返します。
Tomer Wolberg

0

最大インデックスにアクセスしていることがわかっている場合は、最大値にすぐにアクセスできます。したがって、必要なのは最大インデックスだけです。

int max=0;

for(int i = 1; i < arr.Length; i++)
    if (arr[i] > arr[max]) max = i;

0

これはC#バージョンです。これは、配列をソートするという考えに基づいています。

public int solution(int[] A)
 {
    // write your code in C# 6.0 with .NET 4.5 (Mono)
    Array.Sort(A);
    var max = A.Max();
    if(max < 0)
        return 1;
    else
        for (int i = 1; i < max; i++)
        {
            if(!A.Contains(i)) {
                return i;
            }
        }
    return max + 1;
}

0

以下を検討してください。

    /// <summary>
    /// Returns max value
    /// </summary>
    /// <param name="arr">array to search in</param>
    /// <param name="index">index of the max value</param>
    /// <returns>max value</returns>
    public static int MaxAt(int[] arr, out int index)
    {
        index = -1;
        int max = Int32.MinValue;

        for (int i = 0; i < arr.Length; i++)
        {
            if (arr[i] > max)
            { 
                max = arr[i];
                index = i;
            }
        }

        return max;
    }

使用法:

int m, at;
m = MaxAt(new int[]{1,2,7,3,4,5,6}, out at);
Console.WriteLine("Max: {0}, found at: {1}", m, at);

0

これはfor、ゴルフに向かっている場合、ボディレスループで実行できます;)

//a is the array


int mi = a.Length - 1;
for (int i=-1; ++i<a.Length-1; mi=a[mi]<a[i]?i:mi) ;

のチェックで++i<a.Length-1は、最後のインデックスのチェックが省略されます。最大インデックスが最初の最後のインデックスであるかのように設定した場合、これは問題になりません。他の要素に対してループが実行されると、ループは終了し、いずれかがtrueになります。

  • 新しい最大値、したがって新しい最大インデックスが見つかりました mi
  • 最後のインデックスは、すべてに沿って最大値だったので、私たちは新しいを見つけられませんでしたmi、と私たちは初期で立ち往生mi

実際の作業は、ポストループ修飾子によって行われます。

  • これまでに見つけた最大値(a[mi]つまり、でインデックス付けされた配列mi)は、現在のアイテムよりも小さいですか?
    • はい、次にmi覚えて新しいものを保存しますi
    • 既存のものを保存しmiない(何もしない)

操作の最後に、最大値が見つかるインデックスがあります。論理的には、最大値はa[mi]

配列があり、最大値のインデックス、最大値の実際の値がわかっている場合、「最大値と最大値のインデックス」が最大値を追跡するために実際にどのように必要なのか、私にはよくわかりませんでした。インデックスを使用して配列にインデックスを付ける簡単なケースです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.