2012-07-02 9 views
68

tengo esto:rendimiento del índice de mayor valor en una matriz

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

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

+2

así no es como funciona SO. Lea las [preguntas frecuentes] (http://stackoverflow.com/faq) y modifique esta pregunta para incluir el código que ha probado y preguntas específicas sobre cualquier tema con el que tenga problemas. – Dancrumb

+17

Eso no es un duplicado, lea la pregunta ... @Dancrumb La manera en que SO funciona es publicar esta pregunta y en las próximas décadas la gente la encontrará, la leerá y estará agradecida por la información que los colaboradores publicaron a continuación. – Stephen

+1

@Stephen, por el contrario, si lee [estas preguntas frecuentes] (http://stackoverflow.com/faq#dontask), verá que las preguntas subjetivas (como las que comienzan "¿Cuál es la mejor manera ... ") están expresamente desaconsejados. Sin embargo, SO es una comunidad, por lo que corresponde a la comunidad determinar si esta pregunta debe cerrarse o no. – Dancrumb

Respuesta

92

Esta es probablemente la mejor manera, puesto que es fiable y funciona en los 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 presente una sola línea:

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

Se realiza el doble de comparaciones que sea necesario y lanzará un RangeError en arreglos grandes, sin embargo. Me quedaría con la función.

+1

Lo único que no me gusta del primer ejemplo (del que creo que ya te has dado cuenta) es que se repite dos veces innecesariamente.Ciertamente más conciso, sin embargo, te daré eso. –

+1

@DanTao: Sí, es por eso que proporcioné la alternativa. El primero se ve bien, pero se siente desordenado :) – Ryan

+0

Hay un problema con esta función. No es estable. Como está escrito actualmente, devolverá el índice máximo más a la izquierda. Puede probar esto pasando una matriz como [1,2,3,3]. Esto devolverá 2 en lugar de 3. –

5

A menos que me equivoque, diría que es para 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; 
} 
-1

Una versión estable de esta función tiene el siguiente aspecto:

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

¿Qué significa "estable" en este contexto? – Ryan

+0

Supongo que quiso decir "adecuado" – Ikbel

42

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 en lo que va (el índice del elemento máximo hasta el momento, en la primera iteración iMax = 0 porque el segundo argumento es reduce()0 podemos no omite el segundo argumento de reduce() en nuestro caso)
  • x - el elemento actualmente probado de la matriz
  • i - el índice actualmente probado
  • arr - nuestro array ([0, 21, 22, 7])

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

reducir() 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 el segundo, tercer y cuarto argumentos. El primer argumento es el resultado acumulado de la reducción hasta el momento. En la primera llamada a la función, este primer argumento es el valor inicial que pasó como el 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á los primeros y segundos elementos de la matriz como su primer y segundo argumentos .

+8

@traxium Si bien su explicación es excelente, el ejemplo podría ser más claro para los que están menos en la programación funcional si usamos más variables descriptivas. Diga: '' 'arr.reduce ((bestIndexSoFar, currentlyTestedValue, currentlyTestedIndex, array) => currentlyTestedValue> array [bestIndexSoFar]? CurrentlyTestedIndex: bestIndexSoFar, 0);' '', que se puede describir como: iterar la matriz comenzando desde el índice 0 (2º parámetro), si * actualmente ValorPresado * es mayor que el valor del elemento en * bestIndexSoFar *, luego devuelva el * currentlyTestedIndex * a la siguiente iteración como * bestIndexSoFar *. – niieani

+1

@traxium Awesome answer. También estoy de acuerdo con @niieani Este es un ejemplo del mundo real que implementé: 'this.methods.reduce ((methodIndex, currentMethod, currentMethodIndex, methods) => currentMethod.price <= methods [methodIndex] .price? CurrentMethodIndex: methodIndex, 0) '. – Daniel

+1

@DanielK, la respuesta con los nombres de parámetros "completos" no cabrí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

0
var moutains = [3, 1, 5, 9, 4]; 

function findHighestMountainIndex(mountainHeights){ 
    var counter = 1; 
    var indexOfHighestMountain = 0; 

    for(counter; counter < mountainHeights.length; counter++){ 
     if(mountainHeights[indexOfHighestMountain] < mountainHeights[counter]){ 
      indexOfHighestMountain = counter; 
     } 
    } 

    return indexOfHighestMountain; 
} 

console.log(findHighestMountainIndex(mountains)); 

Yo prefiero la forma en que esto se lee. Si el "índice más alto actualmente guardado" es menor que el "índice que se está evaluando", cambie el índice más alto actualmente guardado a lo que se está evaluando actualmente. Luego, a la siguiente iteración. Además, mantener el if-conditional en una sola línea es un buen código limpio.

+0

error en la línea 1: moutains. –

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){ 
 
\t largest =[]; 
 
\t largest.push(arr[i]); 
 
\t } 
 
} 
 
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; 
 
\t if(comp){ 
 
\t arrIndex.push(i); 
 
\t } 
 
} 
 
alert(arrIndex);//[2,3,4]

1

Si usted está utilizando subrayado, puede utilizar este bonito corto de una sola línea:

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

Será en primer lugar encontrar el valor de la partida más importante de la matriz, en este caso 22. Luego devolverá el índice de donde 22 está dentro de la matriz, en este caso 2.

2

Otra solución de max usando redu ce:

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

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

Min través de (conmutación para> y MAX_VALUE):

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