diff --git a/math/algebraic.mbt b/math/algebraic.mbt index 78e8dfd33..404b88785 100644 --- a/math/algebraic.mbt +++ b/math/algebraic.mbt @@ -30,6 +30,25 @@ pub fn maximum[T : Compare](x : T, y : T) -> T { } } +/// Returns the element that gives the maximum value from the specified function. +/// +/// Returns the second argument if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// let abs = fn(n : Int) { if n < 0 { 0 - n } else { n } } +/// print(@math.maximum_by_key(-2, 1, abs)) // output: -2 +/// print(@math.maximum_by_key(-2, 2, abs)) // output: 2 +/// ``` +pub fn maximum_by_key[T, K : Compare](x : T, y : T, f : (T) -> K) -> T { + if f(x) > f(y) { + x + } else { + y + } +} + /// Compares and returns the minimum of two values. /// /// Returns the first argument if the comparison determines them to be equal. @@ -47,3 +66,22 @@ pub fn minimum[T : Compare](x : T, y : T) -> T { x } } + +/// Returns the element that gives the minimum value from the specified function. +/// +/// Returns the first argument if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// let abs = fn(n : Int) { if n < 0 { 0 - n } else { n } } +/// print(@math.minimum_by_key(-2, 1, abs)) // output: 1 +/// print(@math.minimum_by_key(-2, 2, abs)) // output: -2 +/// ``` +pub fn minimum_by_key[T, K : Compare](x : T, y : T, f : (T) -> K) -> T { + if f(x) > f(y) { + y + } else { + x + } +} diff --git a/math/algebraic_test.mbt b/math/algebraic_test.mbt index 608d79a73..c3cfbe4e3 100644 --- a/math/algebraic_test.mbt +++ b/math/algebraic_test.mbt @@ -33,6 +33,13 @@ test "maximum.ref" { @test.is!(@math.maximum(x2t, x2), x2) } +test "maximum_by_key" { + let abs = fn(n : Int) { if n < 0 { 0 - n } else { n } } + assert_eq!(@math.maximum_by_key(1, -2, abs), -2) + assert_eq!(@math.maximum_by_key(-2, 1, abs), -2) + assert_eq!(@math.maximum_by_key(-2, 2, abs), 2) +} + test "minimum.value" { assert_eq!(@math.minimum(1, 2), 1) assert_eq!(@math.minimum(2, 1), 1) @@ -54,6 +61,13 @@ test "minimum.ref" { @test.is!(@math.minimum(x2t, x2), x2t) } +test "minimum_by_key" { + let abs = fn(n : Int) { if n < 0 { 0 - n } else { n } } + assert_eq!(@math.minimum_by_key(1, -2, abs), 1) + assert_eq!(@math.minimum_by_key(-2, 1, abs), 1) + assert_eq!(@math.minimum_by_key(-2, 2, abs), -2) +} + test "exp" { assert_eq!(@math.exp(1), 2.718281828459045) assert_eq!(@math.exp(-1), 0.36787944117144233) diff --git a/math/math.mbti b/math/math.mbti index 4b9349029..e2ca6fa22 100644 --- a/math/math.mbti +++ b/math/math.mbti @@ -25,8 +25,12 @@ fn log2(Double) -> Double fn maximum[T : Compare + Eq](T, T) -> T +fn maximum_by_key[T, K : Compare + Eq](T, T, (T) -> K) -> T + fn minimum[T : Compare + Eq](T, T) -> T +fn minimum_by_key[T, K : Compare + Eq](T, T, (T) -> K) -> T + let pi : Double fn round(Double) -> Double