2012-12-07 11 views
40

Quindi ho un array numerico non numerato int[] anArray = { 1, 5, 2, 7 }; e ho bisogno di ottenere sia il valore che l'indice del valore più grande dell'array che sarebbe 7 e 3, come farei?C# trova il valore dell'array più alto e l'indice

+0

Finora Ive ha provato ad utilizzare il metodo Max() e quindi utilizzare il metodo di ricerca binaria per ottenere l'indice di quel valore massimo ma questo sì non funziona a meno che l'array non sia ordinato, quindi non posso usarlo, quando ho provato che mi ha dato numeri negativi –

+3

Pubblica il tuo codice, per favore. –

+0

@EdmundRojas Non è necessario utilizzare la ricerca binaria. Una semplice ricerca lineare ol funziona perfettamente per liste non ordinate. – millimoose

risposta

63

Questo non è il modo più affascinante ma funziona.

(deve avere using System.Linq;)

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

Hai risparmiato un sacco di tempo per la codifica, ma finirai per passare attraverso la raccolta due volte. –

+3

Non hai nemmeno bisogno di '.ToList()', gli array implementano esplicitamente 'IList' – millimoose

+0

@GaroYeriazarian Se la complessità lineare è troppo per il tuo caso d'uso, probabilmente devi radere di più che ridurre il fattore costante di un terzo. (Anche se ovviamente non è un'ottimizzazione trascurabile.) – millimoose

20

Se l'indice non è ordinato, è necessario scorrere la matrice almeno una volta per trovare il valore più alto. Userei un semplice for ciclo:

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

Questo è più verboso che qualcosa utilizzando LINQ o altre soluzioni di una sola riga, ma è probabilmente un po 'più veloce. Non c'è davvero modo di renderlo più veloce di O (N).

+1

È possibile salvare una iterazione inizializzando 'maxVal' sul valore dell'array all'indice 0 (assumendo che l'array sia almeno lungo 1),' index' a 0 e iniziando il ciclo for a ' i = 1'. –

8

Il LINQ obbligatoria una [1] -liner:

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

(. L'ordinamento è probabilmente un calo di prestazioni rispetto alle altre soluzioni)

[1]: Per valori indicati di uno".

+8

Solo per aggiungere questa soluzione è O (nlogn) la complessità al meglio. La ricerca del massimo può essere ottenuta in tempo O (n) per un array non ordinato. – dopplesoldner

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

// Positioning max 
int p = Array.IndexOf(anArray, m); 
1
anArray.Select((n, i) => new { Value = n, Index = i }) 
    .Where(s => s.Value == anArray.Max()); 
+0

Questa è una soluzione O (n^2), poiché si esegue il calcolo di un array.Max() su ogni iterazione. Questo diventerà molto lento per i grandi array. –

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

uscita per il codice sotto:

00: 00: 00,3279270 - max1 00: 00: 00,2615935 - Max2 00: 00: 00,6010360 - max3 (arr.Max ())

Con 100000000 int a matrice non molto grande differenza, ma ancora ...

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; 
     } 
0
int[] Data= { 1, 212, 333,2,12,3311,122,23 }; 
int large = Data.Max(); 
Console.WriteLine(large); 
+0

La tua risposta fornisce solo il valore più alto, ma il richiedente richiede sia il valore più alto sia l'indice del valore più alto. – Cardin

2

Ecco due approcci. Si consiglia di aggiungere la gestione per quando la matrice è vuota.

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}"); 
} 
0
public static class ArrayExtensions 
{ 
    public static int MaxIndexOf<T>(this T[] input) 
    { 
     var max = input.Max(); 
     int index = Array.IndexOf(input, max); 
     return index; 
    } 
} 

Questo funziona per tutti i tipi di variabili ...

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

Considerate seguente:

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

Usage:

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

Ecco una soluzione LINQ che è O (n) con fattori costanti decenti:

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

Ma si dovrebbe davvero scrivere un esplicito for lop se vi preoccupate per le prestazioni.

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

Solo un'altra prospettiva con DataTable. Dichiarare uno DataTable con 2 colonne chiamate index e val. Aggiungi un'opzione AutoIncrement ed entrambi i valori AutoIncrementSeed e AutoIncrementStep1 alla colonna index. Quindi utilizzare un ciclo foreach e inserire ciascun elemento dell'array nello datatable come riga. Quindi, utilizzando il metodo Select, selezionare la riga con il valore massimo.

Codice

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

uscita

Max Value = 7, Index = 4 

Find a demo here

Problemi correlati