Zwraca indeks największej wartości w tablicy

149

Mam to:

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

Jaki jest najlepszy sposób na zwrócenie indeksu o najwyższej wartości do innej zmiennej?

Stephen
źródło
Uwaga na powyższe odpowiedzi, odpowiedź od LanilT była najszybsza! Zobacz testy porównawcze. const indexOfMaxValue = arr.indexOf (Math.max (... arr)); jsben.ch/6nmd2
Cyprian Bergonia
@CyprianBergonia: Dlaczego moja odpowiedź jest wykluczona z tego testu? Obecnie jest najszybszy: jsben.ch/sxcMG (Cóż, arr.indexOf(Math.max(...arr))to też moja odpowiedź, ale funkcja).
Ry-

Odpowiedzi:

179

To prawdopodobnie najlepszy sposób, ponieważ jest niezawodny i działa na starych przeglądarkach:

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

Jest też jedna linijka:

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

Wykonuje dwa razy więcej porównań, niż jest to konieczne, i będzie jednak RangeErrorgenerować duże tablice. Trzymałbym się funkcji.

Ry-
źródło
1
Ok, ta funkcja zwraca pierwszy napotkany indeks dla największej wartości. Powiedzmy, że mam więcej niż jeden indeks o tej samej najwyższej wartości, jak uzyskać wszystkie te indeksy?
ed1nh0
1
@ ed1nh0: Najłatwiejszym sposobem jest wykonanie wielu przebiegów. Znajdź maksimum za pomocą const max = arr.reduce((m, n) => Math.max(m, n)), a następnie indeksy maksimum to [...arr.keys()].filter(i => arr[i] === max).
Ry-
[...arr.keys()]wyświetla błąd:unexpected token
ed1nh0
@ ed1nh0: Na jaką przeglądarkę / środowisko kierujesz reklamy?
Ry-
Chrom. Używam VueJS i wydaje mi się, że problem dotyczy konfiguracji webpacka.
ed1nh0
85

W jednej linii i prawdopodobnie szybciej 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"

Gdzie:

  • iMax- najlepszy jak dotąd indeks (jak dotąd indeks elementu max, w pierwszej iteracji, iMax = 0ponieważ drugi argument do reduce()to 0, nie możemy reduce()w naszym przypadku pominąć drugiego argumentu do )
  • x - aktualnie testowany element z tablicy
  • i - aktualnie testowany indeks
  • arr- nasza tablica ( [0, 21, 22, 7])

O reduce()metodzie (z „JavaScript: The Definitive Guide” Davida Flanagana):

Redukcja () przyjmuje dwa argumenty. Pierwsza to funkcja, która wykonuje operację redukcji. Zadaniem tej funkcji redukcji jest w jakiś sposób połączenie lub zredukowanie dwóch wartości w jedną wartość i zwrócenie tej zredukowanej wartości.

Funkcje używane w połączeniu z redukuj () różnią się od funkcji używanych z forEach () i map (). Znane wartości, indeksy i tablice są przekazywane jako drugi, trzeci i czwarty argument. Pierwszy argument to skumulowany wynik dotychczasowej redukcji. Przy pierwszym wywołaniu funkcji ten pierwszy argument jest wartością początkową przekazaną jako drugi argument do funkcji redukującej (). Przy kolejnych wywołaniach jest to wartość zwracana przez poprzednie wywołanie funkcji.

Gdy wywołujesz funkcję redukuj () bez wartości początkowej, używa ona pierwszego elementu tablicy jako wartości początkowej. Oznacza to, że pierwsze wywołanie funkcji redukcji będzie miało pierwszy i drugi element tablicy jako pierwszy i drugi argument.

traxium
źródło
12
@traxium Chociaż twoje wyjaśnienie jest świetne, przykład mógłby być jaśniejszy dla tych, którzy mniej interesują się programowaniem funkcjonalnym, gdybyśmy użyli bardziej opisowych zmiennych. Powiedzieć: arr.reduce((bestIndexSoFar, currentlyTestedValue, currentlyTestedIndex, array) => currentlyTestedValue > array[bestIndexSoFar] ? currentlyTestedIndex : bestIndexSoFar, 0);, który można określić jako: iteracji tablica rozpoczynając od indeksu parametrów 0 (2), jeżeli currentlyTestedValue jest wyższa od wartości elementu w bestIndexSoFar , a następnie powrócić do currentlyTestedIndex do następnej iteracji jako bestIndexSoFar .
niieani
1
@traxium Awesome answer. Zgadzam się również z @niieani Oto prawdziwy przykład świat I wdrożone: this.methods.reduce((methodIndex, currentMethod, currentMethodIndex, methods) => currentMethod.price <= methods[methodIndex].price ? currentMethodIndex : methodIndex, 0).
Daniel
2
@DanielK, Odpowiedź z „pełnymi” nazwami parametrów nie zmieściłaby się w jednym wierszu przepełnienia stosu. Pojawiłby się poziomy pasek przewijania i czytanie fragmentu podczas przewijania w poziomie nie byłoby zbyt wygodne. W każdym razie dzięki za sugestie. Zredagowałem odpowiedź w inny sposób.
traxium
@traxium +1 dla rozwiązania FP. Chociaż jest to chorobliwie złożone dla kogoś, kto dopiero zaczyna pracę z JS, Twoje rozwiązanie jest również jednym z najbardziej wydajnych w rozwiązaniu problemu OP.
SeaWarrior404
Według jsben.ch/ujXlk druga metoda jest szybsza.
VFDan
54

Oto inne rozwiązanie, jeśli używasz ES6 z operatorem spreadu:

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

const indexOfMaxValue = arr.indexOf(Math.max(...arr));
Lanil Marasinghe
źródło
7

Kolejne rozwiązanie wykorzystujące max reduce:

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

Zwraca, [5e-324, -1]jeśli tablica jest pusta. Jeśli potrzebujesz tylko indeksu, wstaw [1]po.

Min przez (Zmień na >i MAX_VALUE):

[1,2,5,0,4].reduce((a,b,i) => a[0] > b ? [b,i] : a, [Number.MAX_VALUE,-1])
//[0, 3]
randompast
źródło
6

O ile się nie mylę, powiedziałbym, że chodzi o napisanie własnej funkcji.

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
źródło
Nie radzi sobie dobrze z zerem będącym wartością maksymalną: findIndexOfGreatest( [-5, 0, -10, -1])zwraca 3 ...
traktor53
6

Jeśli używasz podkreślenia, możesz użyć tego ładnego krótkiego, jednowierszowego:

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

Najpierw znajdzie wartość największego elementu w tablicy, w tym przypadku 22. Następnie zwróci indeks miejsca, w którym 22 znajduje się w tablicy, w tym przypadku 2.

Kevin
źródło
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;
}

przejść arraydo haystacki Math.max(...array)do needle. To da wszystkie maksymalne elementy tablicy i jest bardziej rozszerzalne (na przykład musisz również znaleźć wartości minimalne)

Edward Karak
źródło
1

Aby zakończyć pracę @VFDan, przeprowadziłem testy porównawcze 3 metod: zaakceptowaną (pętla niestandardowa), redukuj i znajdź (max (arr)) na tablicy 10000 wartości zmiennoprzecinkowych.

Wyniki na Chromeimum 85 Linux (im wyższy, tym lepszy):

  • niestandardowa pętla: 100%
  • zmniejszyć: 94,36%
  • indexOf (max): 70%

Wyniki w przeglądarce Firefox 80 Linux (im wyższa, tym lepsza):

  • niestandardowa pętla: 100%
  • zmniejszyć: 96,39%
  • indexOf (max): 31,16%

Wniosek:

Jeśli chcesz, aby Twój kod działał szybko, nie używaj indexOf (max). Redukcja jest w porządku, ale użyj niestandardowej pętli, jeśli potrzebujesz najlepszych wyników.

Możesz uruchomić ten test porównawczy w innej przeglądarce, korzystając z tego linku: https://jsben.ch/wkd4c

Matthieu G
źródło
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
źródło
0

EDYCJA: Wiele lat temu podałem odpowiedź, która była obrzydliwa, zbyt szczegółowa i zbyt skomplikowana. Więc go edytuję. Preferuję powyższe odpowiedzi funkcjonalne ze względu na ich zgrabny czynnik, ale nie za ich czytelność; ale gdybym był bardziej zaznajomiony z javascriptem, to też by mi się spodobały.

Pseudo kod:

Indeks śledzenia zawierający największą wartość. Załóżmy, że indeks 0 jest początkowo największy. Porównaj z bieżącym indeksem. W razie potrzeby zaktualizuj indeks z największą wartością.

Kod:

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
źródło
0

Jeśli utworzysz kopię tablicy i posortujesz ją malejąco, pierwszy element kopii będzie największy. Niż możesz znaleźć jego indeks w oryginalnej tablicy.

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

Złożoność czasowa wynosi O (n) dla kopii, O (n * log (n)) dla sortowania i O (n) dla indexOf.

Jeśli chcesz to zrobić szybciej, odpowiedź Ry to O (n).

rodurico
źródło
-1

Stabilna wersja tej funkcji wygląda następująco:

// 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
źródło
Co w tym kontekście oznacza „stabilny”?
Ry-
Myślę, że miał na myśli „odpowiedni”
Ikbel