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ć?


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

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

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


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”.


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.

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

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

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

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

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

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
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.


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


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

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;

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


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

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.