C # encuentra el valor y el índice de matriz más altos

92

Entonces, tengo una matriz numérica sin clasificar int[] anArray = { 1, 5, 2, 7 };y necesito obtener tanto el valor como el índice del valor más grande en la matriz, que sería 7 y 3, ¿cómo haría esto?

Edmund Rojas
fuente
Hasta ahora, he intentado usar el método Max () y luego usar el método de búsqueda binaria para obtener el índice de ese valor máximo, pero esto no funciona a menos que la matriz esté ordenada, por lo que no puedo usarla, cuando intenté que me dio números negativos
Edmund Rojas
@EdmundRojas No es necesario utilizar la búsqueda binaria. Una búsqueda lineal simple funciona bien para listas sin clasificar.
millimoose

Respuestas:

144

Esta no es la forma más glamorosa, pero funciona.

(debe tener using System.Linq;)

 int maxValue = anArray.Max();
 int maxIndex = anArray.ToList().IndexOf(maxValue);
sa_ddam213
fuente
11
Ahorras mucho tiempo de codificación, pero terminarás revisando la colección dos veces.
Garo Yeriazarian
11
Ni siquiera necesita la .ToList()implementación explícita de matricesIList
millimoose
@GaroYeriazarian Si la complejidad lineal es demasiado para su caso de uso, probablemente necesite recortar algo más que reducir el factor constante en un tercio. (Aunque obviamente no es una optimización insignificante).
millimoose
1
@ sa_ddam213 Las matrices implementan la IListinterfaz, pero lo hacen explícitamente: msdn.microsoft.com/en-us/library/… . (Las matrices también implementan la IList<T>interfaz genérica correspondiente .)
millimoose
1
@ sa_ddam213 No, el contrato de ToList()es copiar siempre. Sería una idea terrible que el método a veces se copiara y otras no; esto daría lugar a errores de alias bastante locos. De hecho, la implementación de ToList()es más o menosreturn new List(source)
milimoose
44
int[] anArray = { 1, 5, 2, 7 };
// Finding max
int m = anArray.Max();

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

Si el índice no está ordenado, debe recorrer la matriz al menos una vez para encontrar el valor más alto. Usaría un forbucle 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;
  }
}

Esto es más detallado que algo que usa LINQ u otras soluciones unifilares, pero probablemente sea un poco más rápido. Realmente no hay forma de hacer esto más rápido que O (N).

Tom Hamming
fuente
4
Puede guardar una iteración inicializando maxValcon el valor de la matriz en el índice 0 (asumiendo que la matriz tiene al menos una longitud de 1), indexen 0 y comenzando el ciclo for en i = 1.
Jon Schneider
14

El LINQ one [1] -liner obligatorio:

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

(La clasificación es probablemente un impacto en el rendimiento sobre las otras soluciones).

[1]: para valores dados de "uno".

milimosa
fuente
14
Solo agregar esta solución es la complejidad O (nlogn) en el mejor de los casos. Encontrar max se puede obtener en O (n) tiempo para una matriz sin clasificar.
dopplesoldner
13

Un breve resumen:

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

Caso de prueba:

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.

caracteristicas:

  • Utiliza Linq (no tan optimizado como vainilla, pero la compensación es menos código).
  • No necesita ordenar.
  • Complejidad computacional: O (n).
  • Complejidad espacial: O (n).

Observaciones:

  • Asegúrese de que el número (y no el índice) sea el primer elemento de la tupla porque la clasificación de la tupla se realiza comparando elementos de tupla de izquierda a derecha.
Lesair Valmont
fuente
esto es realmente genial !!
Floydheld
Cabe señalar que para que esto funcione, el elemento que se maximiza debe ser el primero
Caius Jard
¿Qué quieres decir con @CaiusJard? Como se muestra en el caso de prueba, el elemento máximo se encontró correctamente y era el último.
Lesair Valmont
Primero en la Tupla, por ejemplo, anArray.Select((n, i) => ( Index: i, Number: n)).Max()encuentra el índice máximo en lugar del número máximo debido a la forma en que se comparan las tuplas (el elemento 1 es el más significativo, etc.)
Caius Jard
Justo @CaiusJard, agregué un comentario para señalar eso. Gracias.
Lesair Valmont
3

Aquí hay dos enfoques. Es posible que desee agregar manejo para cuando la matriz esté vacía.

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
fuente
1
anArray.Select((n, i) => new { Value = n, Index = i })
    .Where(s => s.Value == anArray.Max());
Adam Nathan
fuente
Esta es una solución O (n ^ 2), porque está calculando anArray.Max () en cada iteración. Eso será muy lento para matrices grandes.
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);
Friki
fuente
1

Salida para el código de abajo:

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

Con 100000000 ints en matriz, no es una gran diferencia, pero aún así ...

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

Esto funciona para todos los tipos 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();
Joe Sonderegger
fuente
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);
}

fuente
0
int[] Data= { 1, 212, 333,2,12,3311,122,23 };
int large = Data.Max();
Console.WriteLine(large);
Jeetendra Negi
fuente
1
Su respuesta solo da el valor más alto, pero el autor de la pregunta solicitó tanto el valor más alto como el índice del valor más alto.
Cardin
0

Aquí hay una solución LINQ que es O (n) con factores constantes decentes:

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

Pero realmente debería escribir un forlop explícito si le importa el rendimiento.

Branko Dimitrijevic
fuente
0

Solo otra perspectiva usando DataTable. Declare a DataTablecon 2 columnas llamadasindex y val. Agregue una AutoIncrementopción y ambos valores AutoIncrementSeedy a la columna. Luego use un bucle e inserte cada elemento de la matriz en una fila. Luego, usando el método, seleccione la fila que tenga el valor máximo.AutoIncrementStep1indexforeachdatatableSelect

Código

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

Salida

Max Value = 7, Index = 4

Encuentre una demostración aquí

Ullas
fuente
0

Encuentra el número más grande y el más pequeño de la matriz:

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
fuente
1
devolverá el último valor que sea mayor / menor que el primer valor de la matriz, no el mínimo / máximo.
Tomer Wolberg
0

Si conoce el índice máximo, el acceso al valor máximo es inmediato. Entonces todo lo que necesitas es un índice máximo.

int max=0;

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

Esta es una versión de C #. Se basa en la idea de ordenar la matriz.

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
fuente
0

Considere lo siguiente:

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

Uso:

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
fuente
0

Esto se puede hacer con un forbucle sin cuerpo , si nos dirigimos hacia el 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) ;

El cheque de ++i<a.Length-1omite chequeando el último índice. No nos importa esto si lo configuramos como si el índice máximo fuera el último índice con el que comenzar. Cuando el ciclo se ejecute para los otros elementos, terminará y una cosa u otra es cierta:

  • encontramos un nuevo valor máximo y, por lo tanto, un nuevo índice máximo mi
  • el último índice fue el valor máximo todo el tiempo, por lo que no encontramos uno nuevo miy nos quedamos con el valor inicialmi

El trabajo real lo realizan los modificadores posteriores al ciclo:

  • ¿Es el valor máximo ( a[mi]es decir, la matriz indexada por mi) que encontramos hasta ahora, menor que el elemento actual?
    • sí, guarda uno nuevo mirecordandoi ,
    • no, entonces almacene el existente mi(no-op)

Al final de la operación, tiene el índice en el que se encuentra el máximo. Lógicamente, entonces el valor máximo esa[mi]

No pude ver cómo el "buscar el máximo y el índice de máximo" realmente necesitaba rastrear el valor máximo también, dado que si tiene una matriz y conoce el índice del valor máximo, el valor real del valor máximo es un caso trivial de usar el índice para indexar la matriz.

Caius Jard
fuente