C # trouve la valeur et l'index de tableau les plus élevés


89

J'ai donc un tableau numérique non trié int[] anArray = { 1, 5, 2, 7 };et j'ai besoin d'obtenir à la fois la valeur et l'index de la plus grande valeur du tableau qui serait 7 et 3, comment puis-je faire cela?


Jusqu'à présent, j'ai essayé d'utiliser la méthode Max (), puis d'utiliser la méthode de recherche binaire pour obtenir l'index de cette valeur maximale, mais cela ne fonctionne pas à moins que le tableau ne soit trié, donc je ne peux pas l'utiliser, quand j'ai essayé qu'il m'a donné des nombres négatifs
Edmund Rojas

@EdmundRojas Vous n'avez pas besoin d'utiliser la recherche binaire. Une recherche linéaire simple fonctionne très bien pour les listes non triées.
millimoose

Réponses:


138

Ce n'est pas la manière la plus glamour mais ça marche.

(doit avoir using System.Linq;)

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

10
Vous économisez beaucoup de temps de codage, mais vous finirez par parcourir la collection deux fois.
Garo Yeriazarian

11
Vous n'avez même pas besoin de l' .ToList()implémentation explicite des tableaux,IList
millimoose

@GaroYeriazarian Si la complexité linéaire est trop importante pour votre cas d'utilisation, vous devez probablement réduire plus que simplement réduire le facteur constant d'un tiers. (Bien que ce ne soit évidemment pas une optimisation négligeable.)
millimoose

1
@ sa_ddam213 Les tableaux implémentent l' IListinterface, mais ils le font explicitement: msdn.microsoft.com/en-us/library/… . (Les tableaux implémentent également l' IList<T>interface générique correspondante .)
millimoose

1
@ sa_ddam213 Non, le contrat ToList()est de toujours copier. Ce serait une idée terrible d'avoir la méthode parfois copiée et parfois non - cela conduirait à des bogues d'alias assez fous. En fait, la mise en œuvre de ToList()est plus ou moinsreturn new List(source)
millimoose

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

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

28

Si l'index n'est pas trié, vous devez parcourir le tableau au moins une fois pour trouver la valeur la plus élevée. J'utiliserais une forboucle simple :

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

C'est plus détaillé que quelque chose utilisant LINQ ou d'autres solutions en une ligne, mais c'est probablement un peu plus rapide. Il n'y a vraiment aucun moyen de rendre cela plus rapide que O (N).


4
Vous pouvez enregistrer une itération en initialisant maxValà la valeur du tableau à l'index 0 (en supposant que le tableau a au moins la longueur 1), indexà 0 et en commençant la boucle for à i = 1.
Jon Schneider

13

Le LINQ one [1] -liner obligatoire:

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

(Le tri est probablement un impact sur les performances par rapport aux autres solutions.)

[1]: Pour des valeurs données de "un".


14
Juste pour ajouter cette solution, c'est au mieux la complexité O (nlogn). La recherche de max peut être obtenue en temps O (n) pour un tableau non trié.
dopplesoldner

13

Un one-liner succinct:

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

Cas de test:

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.

Fonctionnalités:

  • Utilise Linq (pas aussi optimisé que vanilla, mais le compromis est moins de code).
  • N'a pas besoin de trier.
  • Complexité de calcul: O (n).
  • Complexité spatiale: O (n).

Remarques:

  • Assurez-vous que le nombre (et non l'index) est le premier élément du tuple, car le tri par tuple est effectué en comparant les éléments de tuple de gauche à droite.

c'est vraiment chouette !!
floydheld le

Il convient de noter que pour que cela fonctionne, l'élément maximal doit être le premier
Caius Jard

Que voulez-vous dire @CaiusJard? Comme indiqué dans le scénario de test, l'élément maximal a été correctement trouvé et il était le dernier.
Lesair Valmont

Premier dans le tuple, par exemple, anArray.Select((n, i) => ( Index: i, Number: n)).Max()trouve l'index max plutôt que le nombre max en raison de la façon dont les tuples sont comparés (item1 est le plus significatif, etc.)
Caius Jard

Assez juste @CaiusJard, j'ai ajouté une remarque pour le souligner. Merci.
Lesair Valmont

3

Voici deux approches. Vous souhaiterez peut-être ajouter une gestion lorsque le tableau est vide.

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

C'est une solution O (n ^ 2), car vous calculez anArray.Max () à chaque itération. Cela deviendra très lent pour les grands tableaux.
Neil le

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

Sortie pour le code ci-dessous:

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

Avec 100000000 ints en tableau, ce n'est pas une très grande différence mais quand même ...

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

Cela fonctionne pour tous les types de variables ...

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
Votre réponse ne donne que la valeur la plus élevée, mais le demandeur a demandé à la fois la valeur la plus élevée et l'indice de la valeur la plus élevée.
Cardin

0

Voici une solution LINQ qui est O (n) avec des facteurs constants décents:

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

Mais vous devriez vraiment écrire un forlop explicite si vous vous souciez des performances.


0

Juste une autre perspective utilisant DataTable. Déclarez un DataTableavec 2 colonnes appelées indexet val. Ajoutez une AutoIncrementoption et des valeurs AutoIncrementSeedet à la colonne. Ensuite, utilisez une boucle et insérez chaque élément de tableau dans le sous forme de ligne. Ensuite, en utilisant method, sélectionnez la ligne ayant la valeur maximale.AutoIncrementStep1indexforeachdatatableSelect

Code

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

Production

Max Value = 7, Index = 4

Trouvez une démo ici


0

Recherche le plus grand et le plus petit nombre du tableau:

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
il va renvoyer la dernière valeur qui est plus grande / plus petite que la première valeur du tableau, pas le min / max.
Tomer Wolberg le

0

Si vous connaissez max index, l'accès à la valeur max est immédiat. Donc, tout ce dont vous avez besoin est un index max.

int max=0;

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

0

Ceci est une version C #. Il est basé sur l'idée de trier le tableau.

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

Pensez à suivre:

    /// <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 = MaxAt(new int[]{1,2,7,3,4,5,6}, out at);
Console.WriteLine("Max: {0}, found at: {1}", m, at);

0

Cela peut être fait avec une forboucle sans corps, si nous nous dirigeons vers le golf;)

//a is the array


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

Le contrôle des ++i<a.Length-1omet de vérifier le dernier index. Cela ne nous dérange pas si nous le configurons comme si l'index max était le dernier index avec lequel commencer. Lorsque la boucle s'exécute pour les autres éléments, elle se terminera et l'une ou l'autre chose est vraie:

  • nous avons trouvé une nouvelle valeur max et donc un nouvel index max mi
  • le dernier index était la valeur maximale tout au long, donc nous n'avons pas trouvé de nouveau mi, et nous sommes restés avec l'initialemi

Le vrai travail est effectué par les modificateurs post-boucle:

  • est la valeur max ( a[mi]c'est-à-dire le tableau indexé par mi) que nous avons trouvée jusqu'à présent, inférieure à l'élément actuel?
    • oui, puis stocker un nouveau mien se souvenant i,
    • non puis stocker l'existant mi(no-op)

À la fin de l'opération, vous avez l'index auquel le max doit être trouvé. Logiquement, la valeur maximale esta[mi]

Je ne pouvais pas vraiment voir comment le "find max and index of max" avait vraiment besoin de suivre la valeur max, étant donné que si vous avez un tableau et que vous connaissez l'indice de la valeur max, la valeur réelle de la valeur max est un cas trivial d'utilisation de l'index pour indexer le tableau.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.