Last active
March 7, 2023 01:32
-
-
Save engelen/fbce4476c9e68c52ff7e5c2da5c24a28 to your computer and use it in GitHub Desktop.
Single-line ArgMax for JavaScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Retrieve the array key corresponding to the largest element in the array. | |
* | |
* @param {Array.<number>} array Input array | |
* @return {number} Index of array element with largest value | |
*/ | |
function argMax(array) { | |
return array.map((x, i) => [x, i]).reduce((r, a) => (a[0] > r[0] ? a : r))[1]; | |
} | |
console.log(argMax([ 5.2, 1.4, 9.6, 1.8, 3.2, 2.4 ])); | |
// Output: 2 |
Thank you for the snippet, I found this handy.
As you know, the world of JavaScript contains many iterables that don't contain map
. I've tweaked your function to work with any iterable:
function argMax(array) {
return [].map.call(array, (x, i) => [x, i]).reduce((r, a) => (a[0] > r[0] ? a : r))[1];
}
Thank you. It also gives me the idea of a method that runs without first converting [value, index] array:
function argMax(array) {
return [].reduce.call(array, (m, c, i, arr) => c > arr[m] ? i : m, 0)
}
Edit after the @ulrych8's comment: call reduce with an initial value.
@byildiz your function doesn't seem to be working when the array has a length of 2
@ulrych8 thank you for spotting the bug. I editted the code.
If you want to collect all the indices where the array is maximal, then this should work:
/**
* Find List of ArgMax, empty if list is empty
* @param array iterable
* @returns all indices where the Array has the maximal value
*/
export function argMax(array): number[] {
return [].reduce.call(
array,
(aMax: number[], current, idx: number, arr: any[]) => {
// for idx=0, aMax is empty, arr[0] === current, 0 is pushed, then never empty again
const max = arr[aMax[0] || 0];
if (current > max) return [idx];
if (max === current) aMax.push(idx);
return aMax;
},
[]
);
}
With dictionnary-like object you can also do this :
// with [0] at the end it return only the key, without it, it return [maxKey, maxValue]
const argMax = obj => Object.entries(obj).reduce((a, r) => a[1] > r[1] ? a : r)[0]
// or if you need key value and index:
const argMax = obj => Object.entries(obj).map(([k, v], idx) => [k, v, idx]).reduce((a, r) => a[1] > r[1] ? a : r)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note that for TypedArray, it fails as the map function returns a new Array of its original type.