C # znajdź najwyższą wartość tablicy i indeks

92

Mam więc nieposortowaną tablicę liczbową int[] anArray = { 1, 5, 2, 7 };i muszę uzyskać zarówno wartość, jak i indeks największej wartości w tablicy, która będzie równa 7 i 3, jak mam to zrobić?

Edmund Rojas
źródło
Do tej pory próbowałem użyć metody Max (), a następnie użyć metody wyszukiwania binarnego, aby uzyskać indeks tej wartości maksymalnej, ale to nie działa, chyba że tablica jest posortowana, więc nie mogę jej użyć, kiedy próbowałem, że dała mi liczby ujemne
Edmund Rojas
@EdmundRojas Nie musisz używać wyszukiwania binarnego. Zwykłe wyszukiwanie liniowe działa dobrze w przypadku list nieposortowanych.
millimoose

Odpowiedzi:

144

To nie jest najbardziej efektowny sposób, ale działa.

(musi mieć using System.Linq;)

 int maxValue = anArray.Max();
 int maxIndex = anArray.ToList().IndexOf(maxValue);
sa_ddam213
źródło
11
Oszczędzasz dużo czasu na kodowaniu, ale w końcu dwukrotnie przejrzysz kolekcję.
Garo Yeriazarian
11
Nie potrzebujesz nawet .ToList(), tablice jawnie implementowaneIList
millimoose
@GaroYeriazarian Jeśli złożoność liniowa jest zbyt duża dla twojego przypadku użycia, prawdopodobnie będziesz potrzebować więcej niż tylko zredukować stały współczynnik o jedną trzecią. (Chociaż oczywiście nie jest to pomijalna optymalizacja.)
millimoose
1
@ sa_ddam213 Tablice implementują IListinterfejs, ale robią to wyraźnie: msdn.microsoft.com/en-us/library/… . (Tablice również implementują odpowiedni IList<T>interfejs ogólny .)
millimoose
1
@ sa_ddam213 Nie, umowa ToList()dotyczy zawsze kopiowania. Byłoby okropnym pomysłem, gdyby metoda czasami się kopiowała, a czasami nie - prowadziłoby to do całkiem szalonych błędów związanych z aliasowaniem. W rzeczywistości realizacja ToList()jest mniej więcejreturn new List(source)
millimoose
44
int[] anArray = { 1, 5, 2, 7 };
// Finding max
int m = anArray.Max();

// Positioning max
int p = Array.IndexOf(anArray, m);
asr
źródło
28

Jeśli indeks nie jest posortowany, musisz co najmniej raz powtórzyć tablicę, aby znaleźć najwyższą wartość. Użyłbym prostej forpętli:

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

Jest to bardziej szczegółowe niż coś przy użyciu LINQ lub innych rozwiązań jednowierszowych, ale prawdopodobnie jest trochę szybsze. Naprawdę nie ma sposobu, aby zrobić to szybciej niż O (N).

Tom Hamming
źródło
4
Możesz zapisać jedną iterację, inicjując maxValwartość tablicy pod indeksem 0 (zakładając, że tablica ma długość co najmniej 1), indexdo 0 i rozpoczynając pętlę for od i = 1.
Jon Schneider
14

Obowiązkowa LINQ one [1] -liner:

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

(Sortowanie jest prawdopodobnie lepszym rozwiązaniem niż inne rozwiązania).

[1]: Dla podanych wartości „jeden”.

millimoose
źródło
14
Samo dodanie tego rozwiązania to w najlepszym przypadku złożoność O (nlogn). Znalezienie max można uzyskać w czasie O (n) dla nieposortowanej tablicy.
dopplesoldner
13

Zwięzły, jednolinijkowy tekst:

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

Przypadek testowy:

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.

Cechy:

  • Używa Linq (nie tak zoptymalizowany jak wanilia, ale kompromisem jest mniej kodu).
  • Nie trzeba sortować.
  • Złożoność obliczeniowa: O (n).
  • Złożoność przestrzeni: O (n).

Uwagi:

  • Upewnij się, że liczba (a nie indeks) jest pierwszym elementem krotki, ponieważ sortowanie krotek odbywa się poprzez porównywanie elementów krotki od lewej do prawej.
Lesair Valmont
źródło
to jest naprawdę fajne !!
floydheld
Należy zauważyć, że aby to zadziałało, element maksymalny musi być pierwszy
Caius Jard
Co masz na myśli @CaiusJard? Jak pokazano w przypadku testowym, maksymalna pozycja została poprawnie znaleziona i była ostatnia.
Lesair Valmont
Na przykład jako pierwsza w krotce anArray.Select((n, i) => ( Index: i, Number: n)).Max()znajduje indeks maksymalny zamiast maksymalnej liczby ze względu na sposób porównywania krotek (element1 jest najbardziej znaczący itp.)
Caius Jard
W porządku @CaiusJard, dodałem uwagę, aby to podkreślić. Dzięki.
Lesair Valmont
3

Oto dwa podejścia. Możesz chcieć dodać obsługę, gdy tablica jest pusta.

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}");
}
Neil
źródło
1
anArray.Select((n, i) => new { Value = n, Index = i })
    .Where(s => s.Value == anArray.Max());
Adam Nathan
źródło
To jest rozwiązanie O (n ^ 2), ponieważ obliczasz anArray.Max () w każdej iteracji. W przypadku dużych tablic będzie to bardzo powolne.
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);
MANIAK
źródło
1

Dane wyjściowe dla kodu poniżej:

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

Przy 100000000 int w tablicy niezbyt duża różnica, ale nadal ...

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;
        }
Andreas
źródło
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;
    }
}

Działa to dla wszystkich typów zmiennych ...

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();
Joe Sonderegger
źródło
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);
}

źródło
0
int[] Data= { 1, 212, 333,2,12,3311,122,23 };
int large = Data.Max();
Console.WriteLine(large);
Jeetendra Negi
źródło
1
Twoja odpowiedź podaje tylko najwyższą wartość, ale pytający zażądał zarówno najwyższej wartości, jak i indeksu najwyższej wartości.
Cardin
0

Oto rozwiązanie LINQ, które jest O (n) z przyzwoitymi współczynnikami stałymi:

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

Ale naprawdę powinieneś napisać wyraźny forlop, jeśli zależy ci na wydajności.

Branko Dimitrijevic
źródło
0

Po prostu inna perspektywa DataTable. Zadeklaruj a DataTablez 2 kolumnami o nazwie indexi val. Dodaj AutoIncrementopcję oraz oba AutoIncrementSeedi AutoIncrementStepwartości 1do indexkolumny. Następnie użyj foreachpętli i wstaw każdy element tablicy do datatablewiersza. Następnie za pomocą Selectmetody wybierz wiersz o maksymalnej wartości.

Kod

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

Wynik

Max Value = 7, Index = 4

Znajdź tutaj demo

Ullas
źródło
0

Znajduje największą i najmniejszą liczbę w tablicy:

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);
Javidan Akberov
źródło
1
zwróci ostatnią wartość, która jest większa / mniejsza niż pierwsza wartość w tablicy, a nie min / max.
Tomer Wolberg
0

Jeśli wiesz, że indeks maksymalny, dostęp do wartości maksymalnej jest natychmiastowy. Więc wszystko czego potrzebujesz to max index.

int max=0;

for(int i = 1; i < arr.Length; i++)
    if (arr[i] > arr[max]) max = i;
Alex Peter
źródło
0

To jest wersja C #. Opiera się na pomyśle sortowania tablicy.

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

Judavi
źródło
0

Rozważ następujące kwestie:

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

Stosowanie:

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);
BogdanRB
źródło
0

Można to zrobić za pomocą bezcielesnej forpętli, jeśli zmierzamy w stronę golfa;)

//a is the array


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

Sprawdzenie ++i<a.Length-1pomija sprawdzanie ostatniego indeksu. Nie przeszkadza nam to, jeśli ustawimy go tak, jakby indeks maksymalny był ostatnim indeksem, od którego zaczyna się. Gdy pętla zostanie uruchomiona dla innych elementów, zakończy się i jedna lub druga rzecz jest prawdą:

  • znaleźliśmy nową wartość maksymalną, a tym samym nowy indeks maksymalny mi
  • ostatni indeks był przez cały czas wartością maksymalną, więc nie znaleźliśmy nowego mii utknęliśmy z początkiemmi

Prawdziwa praca jest wykonywana przez modyfikatory post-loop:

  • czy maksymalna wartość ( a[mi]tj. tablica indeksowana przez mi), którą znaleźliśmy do tej pory, jest mniejsza niż bieżąca pozycja?
    • tak, a następnie zapisz nowy mi, pamiętając i,
    • nie, potem zapisz istniejący mi(no-op)

Pod koniec operacji masz indeks, na którym znajduje się maksimum. Logicznie więc maksymalna wartość toa[mi]

Nie mogłem do końca zrozumieć, dlaczego funkcja „znajdź maksimum i indeks maksimum” była naprawdę potrzebna do śledzenia wartości maksymalnej, biorąc pod uwagę, że jeśli masz tablicę i znasz indeks wartości maksymalnej, rzeczywista wartość wartości maksymalnej to trywialny przypadek użycia indeksu do indeksowania tablicy.

Caius Jard
źródło