Return index of greatest value in an array

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.


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]

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.