Índice de retorno de mayor valor en una matriz

139

Tengo esto:

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

¿Cuál es la mejor manera de devolver el índice del valor más alto en otra variable?

Stephen
fuente
21
Eso no es un duplicado, lea la pregunta ... @Dancrumb La forma en que SO funciona es que publico esta pregunta y en las próximas décadas la gente la encontrará, la leerá y agradecerá la información que los colaboradores publicaron a continuación.
Stephen
1
@Stephen, por el contrario, si lee estas preguntas frecuentes , verá que las preguntas subjetivas (como las que comienzan con "Cuál es la mejor manera ...") se desaconsejan expresamente. Sin embargo, SO es una comunidad, por lo que corresponde a la comunidad determinar si esta pregunta debe cerrarse o no.
Dancrumb
66
Encontrar el número más grande en una matriz no es lo mismo que encontrar el índice del número más grande en una matriz. Por lo tanto, esta pregunta no es un duplicado de esa referencia publicada como duplicado.
Fzs2
15
Esto NO es un duplicado, o al menos no de la pregunta referenciada. No puedo entender los votos negativos sobre esto: decir que no se puede preguntar en SO la mejor manera de hacer algo es ridículo, y no se requiere un código de ejemplo para una pregunta tan concisa. ¿Cómo es que el 'duplicado' al que se hace referencia tiene +30 votos, y esta pregunta paralela PERO DIFERENTE, formulada en un estilo muy similar, tiene -3 votos? Vuelva a leer la pregunta y elimine sus votos marcados como duplicados. "índice de" es la frase clave que necesita detectar en el título de la pregunta.
panqueque
@Dancrumb El consejo actual en stackoverflow.com/help/dont-ask desalienta las preguntas subjetivas solo si cada respuesta es igualmente válida. En este caso, "mejor" se puede evaluar claramente en términos de rendimiento, concisión y expresividad.
user234461

Respuestas:

165

Esta es probablemente la mejor manera, ya que es confiable y funciona en navegadores antiguos:

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

También hay esta frase:

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

Sin RangeErrorembargo, realiza el doble de comparaciones que sea necesario y arrojará una en matrices grandes. Me apegaría a la función.

Ry-
fuente
1
Ok, esta función devuelve el primer índice encontrado para el mayor valor. Digamos que tengo más de un índice con el mismo valor más alto, ¿cómo obtengo todos estos índices?
ed1nh0
1
@ ed1nh0: La manera fácil es hacer múltiples pases. Encuentre el máximo con const max = arr.reduce((m, n) => Math.max(m, n)), luego los índices del máximo son [...arr.keys()].filter(i => arr[i] === max).
Ry-
[...arr.keys()]genera un error:unexpected token
ed1nh0
@ ed1nh0: ¿A qué navegador / entorno se dirige?
Ry-
Cromo. Estoy usando VueJS y creo que el problema es algo en la configuración del paquete web.
ed1nh0
82

En una línea y probablemente más 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"

Dónde:

  • iMax- el mejor índice hasta ahora (el índice del elemento max hasta ahora, en la primera iteración iMax = 0porque el segundo argumento reduce()es 0, no podemos omitir el segundo argumento reduce()en nuestro caso)
  • x - el elemento actualmente probado de la matriz
  • i - el índice actualmente probado
  • arr- nuestra matriz ( [0, 21, 22, 7])

Sobre el reduce()método (de "JavaScript: la guía definitiva" de David Flanagan):

reduce () toma dos argumentos. La primera es la función que realiza la operación de reducción. La tarea de esta función de reducción es de alguna manera combinar o reducir dos valores en un solo valor, y devolver ese valor reducido.

Las funciones utilizadas con reduce () son diferentes a las funciones utilizadas con forEach () y map (). El valor familiar, el índice y los valores de matriz se pasan como segundo, tercer y cuarto argumento. El primer argumento es el resultado acumulado de la reducción hasta ahora. En la primera llamada a la función, este primer argumento es el valor inicial que pasó como segundo argumento para reducir (). En llamadas posteriores, es el valor devuelto por la invocación previa de la función.

Cuando invoca reduce () sin valor inicial, utiliza el primer elemento de la matriz como valor inicial. Esto significa que la primera llamada a la función de reducción tendrá el primer y el segundo elemento de la matriz como su primer y segundo argumento.

traxio
fuente
12
@traxium Si bien su explicación es excelente, el ejemplo podría ser más claro para quienes tienen menos programación funcional si utilizamos variables más descriptivas. Di: arr.reduce((bestIndexSoFar, currentlyTestedValue, currentlyTestedIndex, array) => currentlyTestedValue > array[bestIndexSoFar] ? currentlyTestedIndex : bestIndexSoFar, 0);, que se puede describir como: Iterar la matriz a partir de índice de 0 (segundo parámetro), si currentlyTestedValue es mayor que el valor del elemento en el bestIndexSoFar , a continuación, devolver el currentlyTestedIndex a la siguiente iteración como la bestIndexSoFar .
niieani
1
@traxium Impresionante respuesta. También estoy de acuerdo con @niieani Aquí está un ejemplo del mundo real implementé: this.methods.reduce((methodIndex, currentMethod, currentMethodIndex, methods) => currentMethod.price <= methods[methodIndex].price ? currentMethodIndex : methodIndex, 0).
Daniel
2
@DanielK, la respuesta con los nombres de los parámetros "completos" no encajaría en una línea de stackoverflow. Aparecería una barra de desplazamiento horizontal y no sería muy conveniente leer el fragmento mientras se desplaza horizontalmente. De todas maneras, gracias por las sugerencias. Edité la respuesta de otra manera.
traxium
@traxium +1 para una solución FP. Si bien es mórbidamente complejo para alguien que acaba de comenzar con JS, su solución también es una de las más eficaces para resolver el problema de OP.
SeaWarrior404
Según jsben.ch/ujXlk , el otro método es más rápido.
VFDan
47

Aquí hay otra solución, si está utilizando ES6 utilizando el operador de propagación:

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

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

A menos que me equivoque, diría que es escribir su propia función.

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

Si está utilizando guiones bajos, puede utilizar este breve resumen:

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

Primero encontrará el valor del elemento más grande en la matriz, en este caso 22. Luego devolverá el índice de donde 22 está dentro de la matriz, en este caso 2.

Kevin
fuente
6

Otra solución de max usando reduce:

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

Esto vuelve [5e-324, -1]si la matriz está vacía. Si solo quieres el índice, ponlo [1]después.

Min via (Cambiar a >y MAX_VALUE):

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

EDITAR: Hace años le di una respuesta a esto que era asquerosa, demasiado específica y demasiado complicada. Entonces lo estoy editando. Estoy a favor de las respuestas funcionales anteriores por su factor ordenado pero no por su legibilidad; pero si estuviera más familiarizado con javascript, entonces también me gustaría para eso.

Pseudocódigo:

Índice de seguimiento que contiene el mayor valor. Suponga que el índice 0 es el más grande inicialmente. Comparar con el índice actual. Actualice el índice con el mayor valor si es necesario.

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
fuente
¡Gracias! Tuve que meterme más con eso.
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;
}

pasar arraya haystacky Math.max(...array)a needle. Esto le dará todos los elementos máximos de la matriz, y es más extensible (por ejemplo, también necesita encontrar valores mínimos)

Edward Karak
fuente
1

Si crea una copia de la matriz y la ordena descendiendo, el primer elemento de la copia será el más grande. Entonces puede encontrar su índice en la matriz original.

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

La complejidad temporal es O (n) para la copia, O (n * log (n)) para la clasificación y O (n) para el indexOf.

Si necesita hacerlo más rápido, la respuesta de Ry es O (n).

rodurico
fuente
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
fuente
-1

Una versión estable de esta función se ve así:

// 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
fuente
¿Qué significa "estable" en este contexto?
Ry-
Supongo que quiso decir "adecuado"
Ikbel
-5

Sencillo

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
fuente
Lo siento, no leí la publicación claramente ahora, actualizaré el código
vidhyesh
explique un poco más su respuesta (ayuda a eliminar los votos negativos) y también intente diferenciarla de otra respuesta (por ejemplo: usar menos recursos o es más rápido en el cálculo ... etc.). (Fin de la revisión de respuestas de baja calidad).
ZF007
Esto no devuelve el índice del valor máximo; esto solo devuelve el valor positivo máximo .
Cœur