Return index of greatest value in an array
Asked Answered
H

15

189

I have this:

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

What's the best way to return the index of the highest value into another variable?

Horvitz answered 2/7, 2012 at 21:27 Comment(2)
Just a note for the provided answers above, answer from LanilT was the fastest! See benchmarks. const indexOfMaxValue = arr.indexOf(Math.max(...arr)); jsben.ch/6nmd2Parthen
@CyprianBergonia: Why’s my answer excluded from that benchmark? It’s currently the fastest: jsben.ch/sxcMG (Well, arr.indexOf(Math.max(...arr)) is also my answer, but the function one.)Michaud
M
234

This is probably the best way, since it’s reliable and works on old browsers:

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

There’s also this one-liner:

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

It performs twice as many comparisons as necessary and will throw a RangeError on large arrays, though. I’d stick to the function.

Michaud answered 2/7, 2012 at 21:29 Comment(2)
Ok this function returns the first encountered index for the greatest value. Let's say I have more than one index with the same highest value, how do I get all these indexes?Favin
@ed1nh0: The easy way is to make multiple passes. Find the max with const max = arr.reduce((m, n) => Math.max(m, n)), then the indexes of the max are [...arr.keys()].filter(i => arr[i] === max).Michaud
F
118

In one line and probably faster then 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"

Where:

  • iMax - the best index so far (the index of the max element so far, on the first iteration iMax = 0 because the second argument to reduce() is 0, we can't omit the second argument to reduce() in our case)
  • x - the currently tested element from the array
  • i - the currently tested index
  • arr - our array ([0, 21, 22, 7])

About the reduce() method (from "JavaScript: The Definitive Guide" by David Flanagan):

reduce() takes two arguments. The first is the function that performs the reduction operation. The task of this reduction function is to somehow combine or reduce two values into a single value, and to return that reduced value.

Functions used with reduce() are different than the functions used with forEach() and map(). The familiar value, index, and array values are passed as the second, third, and fourth arguments. The first argument is the accumulated result of the reduction so far. On the first call to the function, this first argument is the initial value you passed as the second argument to reduce(). On subsequent calls, it is the value returned by the previous invocation of the function.

When you invoke reduce() with no initial value, it uses the first element of the array as the initial value. This means that the first call to the reduction function will have the first and second array elements as its first and second arguments.

Finella answered 15/6, 2015 at 17:4 Comment(6)
@Finella While your explanation is great, the example could be clearer for those less into functional programming if we used more descriptive variables. Say: arr.reduce((bestIndexSoFar, currentlyTestedValue, currentlyTestedIndex, array) => currentlyTestedValue > array[bestIndexSoFar] ? currentlyTestedIndex : bestIndexSoFar, 0);, which can be described as: iterate the array starting from index 0 (2nd parameter), if currentlyTestedValue is higher than the value of the element at the bestIndexSoFar, then return the currentlyTestedIndex to the next iteration as the bestIndexSoFar.Mining
@Finella Awesome answer. I also agree with @Mining Here is a real world example I implemented: this.methods.reduce((methodIndex, currentMethod, currentMethodIndex, methods) => currentMethod.price <= methods[methodIndex].price ? currentMethodIndex : methodIndex, 0).Daddy
@DanielK, The answer with the "full" parameter names wouldn't fit in one stackoverflow line. There would appear a horizontal scroll bar and it'd be not very convenient to read the snippet while horizontally scrolling. Anyway thanks for the suggestions. I edited the answer in another way.Finella
@Finella +1 for a FP solution. While its morbidly complex for someone just starting out with JS, your solution also happens to be one of the most performant ones for solving OP's problem.Clapperclaw
According to jsben.ch/ujXlk, the other method is faster.Bloomsbury
@VFDan, don't use console.log in your benchmarks, this takes way more time that the code that you are actually benchmarking. Also, use larger arrays.Unmanned
U
8

To complete the work of @VFDan, I benchmarked the 3 methods: the accepted one (custom loop), reduce, and find(max(arr)) on an array of 10000 floats.

Results on chromimum 85 linux (higher is better):

  • custom loop: 100%
  • reduce: 94.36%
  • indexOf(max): 70%

Results on firefox 80 linux (higher is better):

  • custom loop: 100%
  • reduce: 96.39%
  • indexOf(max): 31.16%

Conclusion:

If you need your code to run fast, don't use indexOf(max). reduce is ok but use the custom loop if you need the best performances.

You can run this benchmark on other browser using this link: https://jsben.ch/wkd4c

Unmanned answered 18/9, 2020 at 10:47 Comment(0)
O
7

Another solution of max using reduce:

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

This returns [5e-324, -1] if the array is empty. If you want just the index, put [1] after.

Min via (Change to > and MAX_VALUE):

[1,2,5,0,4].reduce((a,b,i) => a[0] > b ? [b,i] : a, [Number.MAX_VALUE,-1])
//[0, 3]
Ozell answered 10/8, 2017 at 7:44 Comment(1)
this does not work on arrays with all negative values (always returns -1 as index)Leinster
G
5

Unless I'm mistaken, I'd say it's to write your own function.

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;
}
Gorlicki answered 2/7, 2012 at 21:31 Comment(1)
Doesn't handle zero being the maximum value well: findIndexOfGreatest( [-5, 0, -10, -1]) returns 3...Merger
R
5

If you are utilizing underscore, you can use this nice short one-liner:

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

It will first find the value of the largest item in the array, in this case 22. Then it will return the index of where 22 is within the array, in this case 2.

Ronnaronnholm answered 20/2, 2017 at 17:12 Comment(1)
this will not be efficient since indexOf will loop the whole array, find the maximum value, and then indexOf will loop it again searching the max value again, wouldn't use it myselfLampoon
M
1

 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]
Moidore answered 29/3, 2016 at 6:5 Comment(0)
F
0

EDIT: Years ago I gave an answer to this that was gross, too specific, and too complicated. So I'm editing it. I favor the functional answers above for their neat factor but not their readability; but if I were more familiar with javascript then I might like them for that, too.

Pseudo code:

Track index that contains largest value. Assume index 0 is largest initially. Compare against current index. Update index with largest value if necessary.

Code:

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
Furbelow answered 31/10, 2015 at 18:26 Comment(0)
E
0
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;
}

pass array to haystack and Math.max(...array) to needle. This will give all max elements of the array, and it is more extensible (for example, you also need to find min values)

Estell answered 6/6, 2019 at 18:13 Comment(0)
R
0

If you create a copy of the array and sort it descending, the first element of the copy will be the largest. Than you can find its index in the original array.

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

Time complexity is O(n) for the copy, O(n*log(n)) for sorting and O(n) for the indexOf.

If you need to do it faster, Ry's answer is O(n).

Regarding answered 6/12, 2019 at 16:32 Comment(0)
I
0

A minor modification revised from the "reduce" version of @traxium 's solution taking the empty array into consideration:

function indexOfMaxElement(array) {
    return array.reduce((iMax, x, i, arr) => 
        arr[iMax] === undefined ? i :
        x > arr[iMax]           ? i : iMax
        , -1            // return -1 if empty
    );
}
Intense answered 10/11, 2021 at 15:39 Comment(0)
I
-1

A stable version of this function looks like this:

// 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;
}
Ima answered 29/4, 2014 at 10:12 Comment(2)
What does “stable” mean in this context?Michaud
I guess he meant "suitable"Bibliology
P
-1

To find the index of the greatest value in an array, copy the original array into the new array and then sort the original array in decreasing order to get the output [22, 21, 7, 0]; now find the value 22 index in the copyNumbers array using this code copyNumbers.indexOf(numbers[0]);

const numbers = [0, 21, 22, 7];
const copyNumbers = [];
copyNumbers.push(...numbers);
numbers.sort(function(a, b) {
  return b - a
});
const index = copyNumbers.indexOf(numbers[0]);
console.log(index);
Piny answered 31/3, 2022 at 7:13 Comment(1)
Looks an awful lot like an existing answer spread out over significantly more lines.Gauger
N
-1

Make this

const max = arr.reduce((m, n) => Math.max(m, n))

then the indexes of the max

get index with findIndex

var index = arr.findIndex(i => i === max)
Nidus answered 7/10, 2022 at 12:13 Comment(1)
That findIndex is just indexOf.Michaud
S
-2

Simple, clear solution using for

const arr = [1, 2, 60, 2, 10, 20];

for (var i = 0, biggerIndex = 0; i < arr.length; i++) {
    if (arr[i] > arr[biggerIndex]) {
        biggerIndex = i;
    }
}

console.log(biggerIndex);
Stricklan answered 10/1, 2024 at 0:50 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.