Portanto, tenho uma matriz numérica não classificada int[] anArray = { 1, 5, 2, 7 };e preciso obter o valor e o índice do maior valor na matriz, que seria 7 e 3, como faria isso?
Até agora, eu tentei usar o método Max () e depois o método de pesquisa binária para obter o índice desse valor máximo, mas isso não funciona a menos que o array seja classificado, então não posso usá-lo, quando tentei, ele me deu números negativos
Edmund Rojas
@EdmundRojas Você não precisa usar a pesquisa binária. Uma pesquisa linear simples funciona bem para listas não classificadas.
milimoose
Respostas:
138
Esta não é a forma mais glamorosa, mas funciona.
(deve ter using System.Linq;)
int maxValue = anArray.Max();int maxIndex = anArray.ToList().IndexOf(maxValue);
Você economiza muito tempo de codificação, mas acabará revisando a coleção duas vezes.
Garo Yeriazarian
11
Você nem precisa dos .ToList()arrays, explicitamente implementaIList
millimoose
@GaroYeriazarian Se a complexidade linear for demais para o seu caso de uso, você provavelmente precisará cortar mais do que apenas reduzir o fator constante em um terço. (Embora obviamente não seja uma otimização desprezível.)
millimoose
1
@ sa_ddam213 Os arrays implementam a IListinterface, mas o fazem explicitamente: msdn.microsoft.com/en-us/library/… . (As matrizes também implementam a IList<T>interface genérica correspondente .)
millimoose
1
@ sa_ddam213 Não, o contrato de ToList()é sempre copiar. Seria uma péssima ideia ter o método às vezes copiado e às vezes não - isso levaria a bugs de aliasing bem malucos. Na verdade, a implementação de ToList()é mais ou menosreturn new List(source)
milimoose
42
int[] anArray ={1,5,2,7};// Finding maxint m = anArray.Max();// Positioning maxint p =Array.IndexOf(anArray, m);
Se o índice não for classificado, você terá que iterar pelo array pelo menos uma vez para encontrar o valor mais alto. Eu usaria um forloop simples :
int? maxVal =null;//nullable so this works even if you have all super-low negativesint index =-1;for(int i =0; i < anArray.Length; i++){int thisNum = anArray[i];if(!maxVal.HasValue|| thisNum > maxVal.Value){
maxVal = thisNum;
index = i;}}
Isso é mais detalhado do que algo usando LINQ ou outras soluções de uma linha, mas provavelmente é um pouco mais rápido. Não há realmente nenhuma maneira de tornar isso mais rápido do que O (N).
Você poderia salvar uma iteração inicializando maxValcom o valor do array no índice 0 (assumindo que o array tenha pelo menos 1 comprimento), indexcom 0 e iniciando o loop for em i = 1.
Jon Schneider
13
O liner obrigatório do LINQ one [1] :
var max = anArray.Select((value, index)=>new{value, index}).OrderByDescending(vi => vi.value).First();
(A classificação provavelmente é um impacto sobre o desempenho das outras soluções.)
Apenas adicionar essa solução é complexidade O (nlogn), na melhor das hipóteses. Encontrar max pode ser obtido em tempo O (n) para uma matriz não classificada.
dopplesoldner de
13
Uma linha sucinta:
var max = anArray.Select((n, i)=>(Number: n,Index: i)).Max();
Caso de teste:
var anArray =newint[]{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.
Recursos:
Usa Linq (não tão otimizado quanto o vanilla, mas a compensação é menos código).
Não precisa classificar.
Complexidade computacional: O (n).
Complexidade do espaço: O (n).
Observações:
Certifique-se de que o número (e não o índice) seja o primeiro elemento na tupla, porque a classificação da tupla é feita comparando os itens da tupla da esquerda para a direita.
Vale ressaltar que para que isso funcione, o item que está sendo maximizado deve ser o primeiro
Caius Jard
O que você quer dizer com @CaiusJard? Conforme mostrado no caso de teste, o item máximo foi encontrado corretamente e foi o último.
Lesair Valmont
Primeiro na Tupla, por exemplo, anArray.Select((n, i) => ( Index: i, Number: n)).Max()encontra o índice máximo em vez do número máximo devido à forma como as tuplas são comparadas (o item1 é o mais significativo etc)
Caius Jard
Muito bem, @CaiusJard, acrescentei uma observação para apontar isso. Obrigado.
Lesair Valmont
3
Aqui estão duas abordagens. Você pode querer adicionar manipulação para quando a matriz estiver vazia.
publicstaticvoidFindMax(){// 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 understandint[]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}");}publicstaticvoidFindMax2(){// Advantages: // * Near-optimal performanceint[]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 conditionfor(int i =0; i <array.Length; i++){intvalue=array[i];if(value> maxInt){
maxInt =value;
maxIndex = i;}}Console.WriteLine($"Maximum int {maxInt} is found at index {maxIndex}");}
publicstaticclassArrayExtensions{publicstaticintMaxIndexOf<T>(this T[] input){var max = input.Max();int index =Array.IndexOf(input, max);return index;}}
Isso funciona para todos os tipos de variáveis ...
vararray=newint[]{1,2,4,10,0,2};var index =array.MaxIndexOf();vararray=newdouble[]{1.0,2.0,4.0,10.0,0.0,2.0};var index =array.MaxIndexOf();
Apenas outra perspectiva usando DataTable. Declare a DataTablecom 2 colunas chamadas indexe val. Adicione uma AutoIncrementopção e ambos os valores AutoIncrementSeede à coluna. Em seguida, use um loop e insira cada item do array como uma linha. Então, usando o método, selecione a linha com o valor máximo.AutoIncrementStep1indexforeachdatatableSelect
Código
int[] anArray ={1,5,2,7};DataTable dt =newDataTable();
dt.Columns.AddRange(newDataColumn[2]{newDataColumn("index"),newDataColumn("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]);
int[] arr =newint[]{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);
Esta é uma versão C #. É baseado na ideia de ordenar o array.
publicint 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)return1;elsefor(int i =1; i < max; i++){if(!A.Contains(i)){return i;}}return max +1;}
/// <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>publicstaticintMaxAt(int[] arr,outint 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(newint[]{1,2,7,3,4,5,6},out at);Console.WriteLine("Max: {0}, found at: {1}", m, at);
Isso pode ser feito com um forloop sem corpo , se estamos indo para o golfe;)
//a is the arrayint mi = a.Length-1;for(int i=-1;++i<a.Length-1; mi=a[mi]<a[i]?i:mi);
A verificação de ++i<a.Length-1omite a verificação do último índice. Não nos importamos se o configurarmos como se o índice máximo fosse o último índice para começar. Quando o loop for executado para os outros elementos, ele terminará e uma ou outra coisa for verdadeira:
encontramos um novo valor máximo e, portanto, um novo índice máximo mi
o último índice era o valor máximo o tempo todo, então não encontramos um novo mie ficamos com o inicialmi
O trabalho real é feito pelos modificadores pós-loop:
é o valor máximo ( a[mi]isto é, array indexado por mi) que encontramos até agora, menor que o item atual?
sim, então guarde um novo milembrando i,
não, então armazene o existente mi(no-op)
No final da operação, você tem o índice no qual o máximo deve ser encontrado. Logicamente, o valor máximo éa[mi]
Não consegui ver como o "find max e index of max" realmente precisava rastrear o valor max também, dado que se você tem uma matriz e sabe o índice do valor max, o valor real do valor max é um caso trivial de usar o índice para indexar a matriz.
Respostas:
Esta não é a forma mais glamorosa, mas funciona.
(deve ter
using System.Linq;
)fonte
.ToList()
arrays, explicitamente implementaIList
IList
interface, mas o fazem explicitamente: msdn.microsoft.com/en-us/library/… . (As matrizes também implementam aIList<T>
interface genérica correspondente .)ToList()
é sempre copiar. Seria uma péssima ideia ter o método às vezes copiado e às vezes não - isso levaria a bugs de aliasing bem malucos. Na verdade, a implementação deToList()
é mais ou menosreturn new List(source)
fonte
Se o índice não for classificado, você terá que iterar pelo array pelo menos uma vez para encontrar o valor mais alto. Eu usaria um
for
loop simples :Isso é mais detalhado do que algo usando LINQ ou outras soluções de uma linha, mas provavelmente é um pouco mais rápido. Não há realmente nenhuma maneira de tornar isso mais rápido do que O (N).
fonte
maxVal
com o valor do array no índice 0 (assumindo que o array tenha pelo menos 1 comprimento),index
com 0 e iniciando o loop for emi = 1
.O liner obrigatório do LINQ one [1] :
(A classificação provavelmente é um impacto sobre o desempenho das outras soluções.)
[1]: Para valores dados de "um".
fonte
Uma linha sucinta:
Caso de teste:
Recursos:
Observações:
fonte
anArray.Select((n, i) => ( Index: i, Number: n)).Max()
encontra o índice máximo em vez do número máximo devido à forma como as tuplas são comparadas (o item1 é o mais significativo etc)Aqui estão duas abordagens. Você pode querer adicionar manipulação para quando a matriz estiver vazia.
fonte
fonte
fonte
Saída para o código abaixo:
00: 00: 00,3279270 - max1 00: 00: 00,2615935 - max2 00: 00: 00,6010360 - max3 (arr.Max ())
Com 100000000 ints na matriz não é uma diferença muito grande, mas ainda ...
fonte
Isso funciona para todos os tipos de variáveis ...
fonte
fonte
fonte
Aqui está uma solução LINQ que é O (n) com fatores constantes decentes:
Mas você realmente deve escrever um
for
lop explícito se você se preocupa com o desempenho.fonte
Apenas outra perspectiva usando
DataTable
. Declare aDataTable
com 2 colunas chamadasindex
eval
. Adicione umaAutoIncrement
opção e ambos os valoresAutoIncrementSeed
e à coluna. Em seguida, use um loop e insira cada item do array como uma linha. Então, usando o método, selecione a linha com o valor máximo.AutoIncrementStep
1
index
foreach
datatable
Select
Código
Resultado
Encontre uma demonstração aqui
fonte
Encontra o maior e o menor número na matriz:
fonte
Se você souber o índice máximo, o acesso ao valor máximo é imediato. Então, tudo que você precisa é o índice máximo.
fonte
Esta é uma versão C #. É baseado na ideia de ordenar o array.
fonte
Considere o seguinte:
Uso:
fonte
Isso pode ser feito com um
for
loop sem corpo , se estamos indo para o golfe;)A verificação de
++i<a.Length-1
omite a verificação do último índice. Não nos importamos se o configurarmos como se o índice máximo fosse o último índice para começar. Quando o loop for executado para os outros elementos, ele terminará e uma ou outra coisa for verdadeira:mi
mi
e ficamos com o inicialmi
O trabalho real é feito pelos modificadores pós-loop:
a[mi]
isto é, array indexado pormi
) que encontramos até agora, menor que o item atual?mi
lembrandoi
,mi
(no-op)No final da operação, você tem o índice no qual o máximo deve ser encontrado. Logicamente, o valor máximo é
a[mi]
Não consegui ver como o "find max e index of max" realmente precisava rastrear o valor max também, dado que se você tem uma matriz e sabe o índice do valor max, o valor real do valor max é um caso trivial de usar o índice para indexar a matriz.
fonte