Índice de retorno de maior valor em uma matriz

139

Eu tenho isto:

var arr = [0, 21, 22, 7];

Qual é a melhor maneira de retornar o índice do valor mais alto para outra variável?

Stephen
fonte
21
Isso não é uma cópia, leia a pergunta… @Dancrumb A maneira como o SO funciona é que eu posto essa pergunta e, nas próximas décadas, as pessoas a encontrarão, lerão e serão gratas pelas informações que os colaboradores postaram abaixo!
Stephen
1
@ Stephen, pelo contrário, se você ler esta FAQ , verá que perguntas subjetivas (como as que começam com "Qual é a melhor maneira ...") são expressamente desencorajadas. No entanto, o SO é uma comunidade, portanto cabe à comunidade determinar se essa pergunta deve ser encerrada ou não.
Dancrumb
6
Encontrar o maior número em uma matriz não é o mesmo que encontrar o índice do maior número em uma matriz. Portanto, esta pergunta não é uma duplicata dessa referência publicada como duplicada.
Fzs2
15
Esta NÃO é uma duplicata - ou pelo menos não é da questão referenciada. Eu não consigo entender os votos negativos sobre isso - dizer que você não pode perguntar a SO, a melhor maneira de fazer algo é ridículo, e nenhum exemplo de código é necessário para uma pergunta tão concisa. Como é que o 'duplicado' referenciado tem +30 votos, e essa pergunta paralela MAS DIFERENTE, feita de maneira muito semelhante, tem -3 votos? Releia a pergunta e remova seus votos marcados como duplicados. "índice de" é a frase-chave que você precisa identificar no título da pergunta.
pancake
@Dancrumb Os conselhos atuais em stackoverflow.com/help/dont-ask desencorajam perguntas subjetivas apenas se todas as respostas forem igualmente válidas. Nesse caso, o "melhor" pode ser claramente avaliado em termos de desempenho, concisão e expressividade.
usar o seguinte comando

Respostas:

165

Esta é provavelmente a melhor maneira, pois é confiável e funciona em navegadores antigos:

function indexOfMax(arr) {
    if (arr.length === 0) {
        return -1;
    }

    var max = arr[0];
    var maxIndex = 0;

    for (var i = 1; i < arr.length; i++) {
        if (arr[i] > max) {
            maxIndex = i;
            max = arr[i];
        }
    }

    return maxIndex;
}

Há também este one-liner:

let i = arr.indexOf(Math.max(...arr));

Ele realiza o dobro de comparações necessárias e, RangeErrorno entanto, gera uma matriz grande. Eu manteria a função.

Ry-
fonte
1
Ok, esta função retorna o primeiro índice encontrado para o maior valor. Digamos que eu tenha mais de um índice com o mesmo valor mais alto, como obtenho todos esses índices?
Ed1nh0 15/04/19
1
@ ed1nh0: A maneira mais fácil é fazer vários passes. Encontre o máximo com const max = arr.reduce((m, n) => Math.max(m, n)), então os índices do máximo são [...arr.keys()].filter(i => arr[i] === max).
Ry-
[...arr.keys()]gera um erro:unexpected token
ed1nh0 22/04/19
@ ed1nh0: Qual navegador / ambiente você está alvejando?
Ry-
Cromada. Estou usando o VueJS e acho que o problema está relacionado à configuração do webpack.
Ed1nh0 24/04/19
82

Em uma linha e provavelmente mais rápido que arr.indexOf(Math.max.apply(Math, arr)):

var a = [0, 21, 22, 7];
var indexOfMaxValue = a.reduce((iMax, x, i, arr) => x > arr[iMax] ? i : iMax, 0);

document.write("indexOfMaxValue = " + indexOfMaxValue); // prints "indexOfMaxValue = 2"

Onde:

  • iMax- o melhor índice até agora (o índice do elemento max até o momento, na primeira iteração iMax = 0porque o segundo argumento reduce()é 0, não podemos omitir o segundo argumento reduce()no nosso caso)
  • x - o elemento atualmente testado da matriz
  • i - o índice atualmente testado
  • arr- nossa matriz ( [0, 21, 22, 7])

Sobre o reduce()método (de "JavaScript: The Definitive Guide", de David Flanagan):

reduzir () leva dois argumentos. A primeira é a função que executa a operação de redução. A tarefa dessa função de redução é de alguma forma combinar ou reduzir dois valores em um único valor e retornar esse valor reduzido.

As funções usadas com reduzir () são diferentes das funções usadas com forEach () e mapa (). O valor familiar, o índice e os valores da matriz são passados ​​como segundo, terceiro e quarto argumentos. O primeiro argumento é o resultado acumulado da redução até o momento. Na primeira chamada para a função, esse primeiro argumento é o valor inicial que você passou como o segundo argumento para reduzir (). Nas chamadas subseqüentes, é o valor retornado pela chamada anterior da função.

Quando você invoca reduzir () sem valor inicial, ele usa o primeiro elemento da matriz como valor inicial. Isso significa que a primeira chamada para a função de redução terá o primeiro e o segundo elementos da matriz como primeiro e segundo argumentos.

traxium
fonte
12
@traxium Embora a sua explicação seja ótima, o exemplo poderia ser mais claro para aqueles que menos entendem de programação funcional se usarmos variáveis ​​mais descritivas. Diga: arr.reduce((bestIndexSoFar, currentlyTestedValue, currentlyTestedIndex, array) => currentlyTestedValue > array[bestIndexSoFar] ? currentlyTestedIndex : bestIndexSoFar, 0);, o que pode ser descrito como: iterar a matriz a partir de índice 0 (segundo parâmetro), se currentlyTestedValue é maior do que o valor do elemento no bestIndexSoFar , em seguida, voltar a currentlyTestedIndex para a iteração seguinte como a bestIndexSoFar .
Niieani 14/10/2015
1
@traxium Resposta impressionante. Concordo também com @niieani Aqui está um exemplo do mundo real Eu implementados: this.methods.reduce((methodIndex, currentMethod, currentMethodIndex, methods) => currentMethod.price <= methods[methodIndex].price ? currentMethodIndex : methodIndex, 0).
Daniel
2
@ DanielK, a resposta com os nomes de parâmetro "completos" não caberia em uma linha de fluxo de pilha. Apareceria uma barra de rolagem horizontal e não seria muito conveniente ler o trecho enquanto rolava horizontalmente. De qualquer forma, obrigado pelas sugestões. Eu editei a resposta de outra maneira.
traxium
@traxium +1 para uma solução FP. Embora seja morbidamente complexo para alguém que está começando com o JS, sua solução também é uma das de maior desempenho para solucionar o problema do OP.
SeaWarrior404
De acordo com jsben.ch/ujXlk , o outro método é mais rápido.
VFDan 18/02
47

Aqui está outra solução: se você estiver usando o ES6 usando o operador spread:

var arr = [0, 21, 22, 7];

const indexOfMaxValue = arr.indexOf(Math.max(...arr));
Lanil Marasinghe
fonte
6

A menos que eu esteja enganado, eu diria que é escrever sua própria função.

function findIndexOfGreatest(array) {
  var greatest;
  var indexOfGreatest;
  for (var i = 0; i < array.length; i++) {
    if (!greatest || array[i] > greatest) {
      greatest = array[i];
      indexOfGreatest = i;
    }
  }
  return indexOfGreatest;
}
Dan Tao
fonte
6

Se você estiver utilizando sublinhado, poderá usar esta bela linha curta:

_.indexOf(arr, _.max(arr))

Ele primeiro encontrará o valor do maior item da matriz, neste caso 22. Em seguida, retornará o índice de onde 22 está dentro da matriz, neste caso 2.

Kevin
fonte
6

Outra solução do max usando reduce:

[1,2,5,0,4].reduce((a,b,i) => a[0] < b ? [b,i] : a, [Number.MIN_VALUE,-1])
//[5,2]

Isso retorna [5e-324, -1]se a matriz estiver vazia. Se você quiser apenas o índice, coloque[1] depois.

Min via (Alterar para >e MAX_VALUE):

[1,2,5,0,4].reduce((a,b,i) => a[0] > b ? [b,i] : a, [Number.MAX_VALUE,-1])
//[0, 3]
randompast
fonte
1

Edição: Anos atrás, eu dei uma resposta para isso que era nojento, específico demais e complicado demais. Então, eu estou editando. Eu sou a favor das respostas funcionais acima por seu fator elegante, mas não por sua legibilidade; mas se eu estivesse mais familiarizado com o javascript, talvez também gostasse deles.

Pseudo-código:

Índice de faixas que contém o maior valor. Suponha que o índice 0 seja o maior inicialmente. Compare com o índice atual. Atualize o índice com o maior valor, se necessário.

Código:

var mountains = [3, 1, 5, 9, 4];

function largestIndex(array){
  var counter = 1;
  var max = 0;

  for(counter; counter < array.length; counter++){
    if(array[max] < array[counter]){
        max = counter;
    }
  }
  return max;
}

console.log("index with largest value is: " +largestIndex(mountains));
// index with largest value is: 3
Ross Studtman
fonte
Obrigado! Eu tive que mexer com isso ainda mais.
Ross studtman
1
function findIndicesOf(haystack, needle)
{
    var indices = [];

    var j = 0;
    for (var i = 0; i < haystack.length; ++i) {
        if (haystack[i] == needle)
            indices[j++] = i;
    }
    return indices;
}

passar arraypara haystacke Math.max(...array)para needle. Isso fornecerá todos os elementos máximos da matriz e é mais extensível (por exemplo, você também precisa encontrar valores mínimos)

Edward Karak
fonte
1

Se você criar uma cópia da matriz e ordená-la em ordem decrescente, o primeiro elemento da cópia será o maior. Do que você pode encontrar o seu índice na matriz original.

var sorted = [...arr].sort((a,b) => b - a)
arr.indexOf(sorted[0])

A complexidade de tempo é O (n) para a cópia, O (n * log (n)) para classificação e O (n) para o indexOf.

Se você precisar fazer isso mais rapidamente, a resposta de Ry é O (n).

rodurico
fonte
0

 var arr=[0,6,7,7,7];
 var largest=[0];
 //find the largest num;
 for(var i=0;i<arr.length;i++){
   var comp=(arr[i]-largest[0])>0;
      if(comp){
	  largest =[];
	  largest.push(arr[i]);
	  }
 }
 alert(largest )//7
 
 //find the index of 'arr'
 var arrIndex=[];
 for(var i=0;i<arr.length;i++){
    var comp=arr[i]-largest[0]==0;
	if(comp){
	arrIndex.push(i);
	}
 }
 alert(arrIndex);//[2,3,4]

mos wen
fonte
-1

Uma versão estável desta função é semelhante a esta:

// not defined for empty array
function max_index(elements) {
    var i = 1;
    var mi = 0;
    while (i < elements.length) {
        if (!(elements[i] < elements[mi]))
            mi = i;
        i += 1;
    }
    return mi;
}
Peter Stuifzand
fonte
O que significa "estável" neste contexto?
Ry-
Eu acho que ele quis dizer "adequado"
Ikbel 18/12/16
-5

Simples

maxarr: function(){
let maxval = 0;
let maxindex = null;
for (i = 0; i < arr.length; i++){
if (arr[i] > maxval) {
maxval = arr[i];
maxindex = i;
}
}
}
vidhyesh
fonte
Desculpe ENTENDI't claramente ler o post agora eu vou atualizar o código
vidhyesh
por favor, explique um pouco mais a sua resposta (ajuda a remover os votos negativos) e tente diferenciá-la de outra resposta (ieeg: usando menos recursos ou é mais rápido no cálculo ... etc). (Fim da revisão da resposta de baixa qualidade).
ZF007 23/11/19
Isso não retorna o índice do valor máximo; isso apenas retorna o valor positivo máximo .
Cœur