2012-07-02 8 views
68

ho questo:Return Index di maggior valore in un array

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

Qual è il modo migliore per restituire l'indice del valore più alto in un'altra variabile?

+2

non è così che funziona così. Leggi le [domande frequenti] (http://stackoverflow.com/faq) e modifica questa domanda per includere il codice che hai provato e domande specifiche su qualsiasi cosa tu stia riscontrando problemi. – Dancrumb

+17

Questo non è un duplicato, leggi la domanda ... @Dancrumb Il modo in cui SO funziona è postare questa domanda e per decenni a venire la gente la troverà, la leggerà e sarà grata per le informazioni che i contributori hanno pubblicato qui sotto! – Stephen

+1

@Stephen, al contrario, se leggi [questa FAQ] (http://stackoverflow.com/faq#dontask), vedrai che le domande soggettive (come quelle che iniziano "Qual è il modo migliore ... ") sono espressamente scoraggiati. Tuttavia, SO è una comunità, quindi è compito della comunità determinare se questa domanda debba essere chiusa o meno. – Dancrumb

risposta

92

Questo è probabilmente il modo migliore, dal momento che è affidabile e funziona su vecchi browser:

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

C'è anche questo one-liner:

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

Svolge il doppio di molti paragoni come è necessario e lancerà uno RangeError su grandi matrici, però. Mi attenerei alla funzione.

+1

L'unica cosa che non mi piace del primo esempio (che penso tu abbia già capito) è che itera due volte inutilmente.Certamente più conciso, però ... te lo darò. –

+1

@DanTao: Sì, è per questo che ho fornito l'alternativa. Il primo sembra bello, ma si sente in disordine :) – Ryan

+0

C'è un problema con questa funzione. Non è stabile Come è attualmente scritto, restituirà l'indice massimo più a sinistra. Puoi provare questo passando un array come [1,2,3,3]. Ciò restituirà 2 invece di 3. –

5

A meno che non mi sbagli, direi che è per scrivere la tua funzione.

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 versione stabile di questa funzione si presenta così:

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

Cosa significa "stabile" in questo contesto? – Ryan

+0

Immagino che intendesse "adatto" – Ikbel

42

In una riga e probabilmente più veloce poi 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"

Dove:

  • iMax - il miglior indice finora (l'indice dell'elemento massimo finora, alla prima iterazione iMax = 0 perché il secondo argomento di reduce() è 0, non possiamo omettere il secondo argomento reduce() nel nostro caso)
  • x - l'elemento attualmente testato dalla matrice
  • i - l'indice attualmente testato
  • arr - nostra matrice ([0, 21, 22, 7])

Circa il metodo reduce() (da "JavaScript: The Definitive Guide" di David Flanagan):

ridurre() accetta due argomenti. La prima è la funzione che esegue l'operazione di riduzione. Il compito di questa funzione di riduzione è in qualche modo combinare o ridurre due valori in un singolo valore e restituire quel valore ridotto.

Le funzioni utilizzate con reduce() sono diverse dalle funzioni utilizzate con forEach() e map(). Il valore familiare, l'indice e i valori dell'array vengono passati come secondo, terzo e quarto argomento. Il primo argomento è il risultato accumulato della riduzione fino ad ora. Alla prima chiamata alla funzione, questo primo argomento è il valore iniziale passato come argomento secondo to reduce(). Nelle chiamate successive, è il valore restituito dall'invocazione precedente della funzione.

Quando si richiabbe reduc() senza valore iniziale, utilizza il primo elemento dell'array come valore iniziale.Ciò significa che la prima chiamata alla funzione di riduzione avrà il primo e il secondo elemento di matrice come primo e secondo argomento .

+8

@traxium Mentre la tua spiegazione è ottima, l'esempio potrebbe essere più chiaro per quelli meno in programmazione funzionale se usassimo variabili più descrittive. Dì: '' 'arr.reduce ((bestIndexSoFar, currentlyTestedValue, currentlyTestIndex, array) => currentTestValue> array [bestIndexSoFar]? CurrentlyTestedIndex: bestIndexSoFar, 0);' '', che può essere descritto come: iterare l'array a partire dall'indice 0 (2 ° parametro), se * currentTestedValue * è superiore al valore dell'elemento in * bestIndexSoFar *, quindi restituire * currentTestedIndex * alla successiva iterazione come * bestIndexSoFar *. – niieani

+1

@traxium Risposta stupenda. Sono d'accordo anche con @niieani Ecco un esempio del mondo reale che ho implementato: 'this.methods.reduce ((methodIndex, currentMethod, currentMethodIndex, methods) => currentMethod.price <= metodi [metodoIndice] .price? CurrentMethodIndex: methodIndex, 0) '. – Daniel

+1

@DanielK, la risposta con i nomi dei parametri "completi" non si adatterebbe in una riga StackOverflow. Apparirà una barra di scorrimento orizzontale e non sarebbe molto comodo leggere lo snippet mentre si scorre orizzontalmente. Comunque grazie per i suggerimenti. Ho modificato la risposta in un altro modo. Errore – 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)); 

preferisco il modo in cui questa legge. Se "l'indice più alto attualmente salvato" è inferiore a "l'indice valutato", modifica l'indice più alto attualmente salvato con quello che viene attualmente valutato. Quindi alla prossima iterazione. Inoltre, mantenere l'if-condizionale su una singola riga è un bel po 'di codice pulito.

+0

sulla riga 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

Se si sta utilizzando sottolineatura, è possibile utilizzare questo bel breve one-liner:

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

Sarà prima trovare il valore della voce più grande nella matrice, in questo caso 22. Quindi restituirà l'indice di dove 22 è all'interno dell'array, in questo caso 2.

2

Un'altra soluzione di max utilizzando redu ce:

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

Restituisce [5e-324, -1] se l'array è vuoto. Se vuoi solo l'indice, metti [1] dopo.

Min via (commutazione per> e MAX_VALUE):

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