Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Math.{minIndex, maxIndex} #3

Open
caub opened this issue Aug 27, 2016 · 7 comments
Open

Math.{minIndex, maxIndex} #3

caub opened this issue Aug 27, 2016 · 7 comments

Comments

@caub
Copy link

caub commented Aug 27, 2016

Something I often need is to get the index of a minimum in an array, not especially its value

Math.inf([6,4,5]) // 1
Math.sup([6,4,5]) // 0
// or this naming:
Math.minIndex([6,4,5]) // 1 
Math.maxIndex([6,4,5]) // 0
// or 
Math.argMin([6, 4, 5]) // 1
Math.argMax([6,4,5]) // 0
Math.argMin(6, 4, 5) // possibly as a variadic function?
@caub caub changed the title argmin/argmax Math.sup/Math.inf or Math.argmin/Math.argmax Sep 30, 2016
@caub caub changed the title Math.sup/Math.inf or Math.argmin/Math.argmax Math.inf/Math.sup or Math.minIndex/Math.maxIndex or Math.argmin/Math.argmax Sep 30, 2016
@caub caub changed the title Math.inf/Math.sup or Math.minIndex/Math.maxIndex or Math.argmin/Math.argmax Math.{inf, sup} Sep 30, 2016
@ghost
Copy link

ghost commented Oct 31, 2016

In mathematics, inf, sup and argmax have very precise definitions (which don't match your test cases above).

Math.minIndex and Math.maxIndex are much more analogous to Math.min and Math.max. This naming is also consistent with Array.prototype.find and Array.prototype.findIndex.

@caub caub changed the title Math.{inf, sup} Math.{minIndex, maxIndex} Oct 31, 2016
@caub
Copy link
Author

caub commented Jul 8, 2017

// 1 year.. still no Math.maxIndex in sight..
const maxI = a => { const x=Math.max(...a); return a.indexOf(x) };
// or const maxI = a => a.reduce((i, _, j) => a[j]>a[i]?j:i, 0);
// I leave this comment for people in 2025 :p

@imjasonmiller
Copy link

I'd (still) love to have this functionality as well, but as a small nit, it seems somewhat of a constraint to me to define this directly on the Math object? Wouldn't defining it on arrays make it more versatile?

[4, 2, 4, 2].minIndex() === 1
[4, 2, 4, 2].reverse().minIndex() === 0

I often use position_min() and position_max() in Rust, which are defined in a similar manner and are part of the popular Itertools crate.

@Andrew-Cottrell
Copy link

Andrew-Cottrell commented Feb 6, 2021

These implementations make a single pass through the array

function indexOfMax(array) {
    return array.reduce((a, v, i) => 1 in a && v <= a[1] ? a : [i, v], [-1])[0];
}

function indexOfMin(array) {
    return array.reduce((a, v, i) => 1 in a && v >= a[1] ? a : [i, v], [-1])[0];
}

function lastIndexOfMax(array) {
    return array.reduceRight((a, v, i) => 1 in a && v <= a[1] ? a : [i, v], [-1])[0];
}

function lastIndexOfMin(array) {
    return array.reduceRight((a, v, i) => 1 in a && v >= a[1] ? a : [i, v], [-1])[0];
}

Examples

indexOfMax( [] );                // -1
indexOfMax( [ 4, 2, 4, 2 ] );    // 0
indexOfMax( [ 1n, 1n, 4n ] );    // 2
indexOfMax( [ "a", "b", "c" ] ); // 2

indexOfMin( [] );                // -1
indexOfMin( [ 4, 2, 4, 2 ] );    // 1
indexOfMin( [ 4n, 1n, 4n ] );    // 1
indexOfMin( [ "x", "a", "z" ] ); // 1

I'm not convinced it is worth these being built-in; they could easily be made available in a JavaScript library.

If they are to be built-in, I suggest they be methods on the Array.prototype object rather than functions on the Math object.

@ljharb
Copy link

ljharb commented Feb 6, 2021

Why should they be methods on Array.prototype, when Math.max/Math.min already establishes the precedent for a Math function that takes a list of arguments?

@imjasonmiller
Copy link

imjasonmiller commented Feb 7, 2021

Why should they be methods on Array.prototype

Hi @ljharb! I think of it as a function that perhaps should work on more than just Number and on any value that can be compared to another:

let names = ["a", "d", "c", "b"].maxIndex(); // 1 ("d"), as its code point is U+0044

Rust's Itertools, as precedent, implements it in a similar manner:

use itertools::Itertools;

["a", "d", "b", "c"].iter().position_max() // Some(1)

Array.prototype is also the first place I would look for a method that returns an index, akin to:

Next to that, I personally find it more ergonomic and easier on the eyes when chaining, e.g:

let values = [ { re: 3, im: 4 }, { re: 8, im: 0 }, { re: 6, im: 8 } ];

const maxAbsIndex = (values) =>
  Math.maxIndex(values.map(({ re, im }) => Math.hypot(re, im)));

const maxAbsIndex = (values) =>
  values.map(({ re, im }) => Math.hypot(re, im)).maxIndex();

I'm not a big fan of the extra level of nesting that comes with Math.maxIndex() and think it would work better for the imperative and functional approach, especially with larger chains in case of the latter.

@ljharb
Copy link

ljharb commented Feb 7, 2021

Rust appears to implement it on iterators, not arrays (based on your example)

It’s a good point that being indexes implies it’s for arrays and nothing else (even generic iterators don’t really have indexes).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants