From ff3e83855328c0531dfb39e40caf64b413610133 Mon Sep 17 00:00:00 2001 From: Fardale Date: Wed, 12 Apr 2023 11:52:57 +0200 Subject: [PATCH] CCArray(feat): Add max,argmax,min,argmin and their _exn conterpart --- src/core/CCArray.ml | 56 +++++++++++++++++++++++++++++++++++++- src/core/CCArray.mli | 41 ++++++++++++++++++++++++++++ src/core/CCArrayLabels.mli | 41 ++++++++++++++++++++++++++++ tests/core/t_array.ml | 16 +++++++++++ 4 files changed, 153 insertions(+), 1 deletion(-) diff --git a/src/core/CCArray.ml b/src/core/CCArray.ml index 9ac0d744..d8e2301f 100644 --- a/src/core/CCArray.ml +++ b/src/core/CCArray.ml @@ -153,6 +153,60 @@ let find_idx p a = None) a 0 +let max cmp a = + if Array.length a = 0 then None + else Some ( + fold + (fun acc elt -> if cmp acc elt < 0 then elt else acc) + a.(0) + a) + +let max_exn cmp a = + match max cmp a with + | None -> invalid_arg __FUNCTION__ + | Some elt -> elt + + +let argmax cmp a = + if Array.length a = 0 then None + else Some ( + foldi + (fun acc i elt -> if cmp a.(acc) elt < 0 then i else acc) + 0 + a) + +let argmax_exn cmp a = + match argmax cmp a with + | None -> invalid_arg __FUNCTION__ + | Some elt -> elt + +let min cmp a = + if Array.length a = 0 then None + else Some ( + fold + (fun acc elt -> if cmp acc elt > 0 then elt else acc) + a.(0) + a) + +let min_exn cmp a = + match min cmp a with + | None -> invalid_arg __FUNCTION__ + | Some elt -> elt + + +let argmin cmp a = + if Array.length a = 0 then None + else Some ( + foldi + (fun acc i elt -> if cmp a.(acc) elt > 0 then i else acc) + 0 + a) + +let argmin_exn cmp a = + match argmin cmp a with + | None -> invalid_arg __FUNCTION__ + | Some elt -> elt + let filter_map f a = let rec aux acc i = if i = Array.length a then ( @@ -275,7 +329,7 @@ let rec _exists2 p a1 a2 i1 i2 ~len = && (p a1.(i1) a2.(i2) || _exists2 p a1 a2 (i1 + 1) (i2 + 1) ~len:(len - 1)) let exists2 p a b = - _exists2 p a b 0 0 ~len:(min (Array.length a) (Array.length b)) + _exists2 p a b 0 0 ~len:(Stdlib.min (Array.length a) (Array.length b)) let _fold2 f acc a b i j ~len = let rec aux acc o = diff --git a/src/core/CCArray.mli b/src/core/CCArray.mli index 89970e24..8c56355d 100644 --- a/src/core/CCArray.mli +++ b/src/core/CCArray.mli @@ -142,6 +142,47 @@ val find_idx : ('a -> bool) -> 'a t -> (int * 'a) option and [f x] holds. Otherwise returns [None]. @since 0.3.4 *) +val max : ('a -> 'a -> int) -> 'a t -> 'a option +(** [max cmp a] returns [None] if [a] is empty, otherwise, returns [Some e] where [e] + is a maximum element in [a] with respect to [cmp]. + @since NEXT_RELEASE *) + +val max_exn : ('a -> 'a -> int) -> 'a t -> 'a +(** [max_exn cmp a] is like {!max}, but + @raise Invalid_argument if [a] is empty. + @since NEXT_RELEASE *) + + +val argmax : ('a -> 'a -> int) -> 'a t -> int option +(** [argmax cmp a] returns [None] if [a] is empty, otherwise, returns [Some i] where [i] + is the index of a maximum element in [a] with respect to [cmp]. + @since NEXT_RELEASE *) + +val argmax_exn : ('a -> 'a -> int) -> 'a t -> int +(** [argmax_exn cmp a] is like {!argmax}, but + @raise Invalid_argument if [a] is empty. + @since NEXT_RELEASE *) + +val min : ('a -> 'a -> int) -> 'a t -> 'a option +(** [min cmp a] returns [None] if [a] is empty, otherwise, returns [Some e] where [e] + is a minimum element in [a] with respect to [cmp]. + @since NEXT_RELEASE *) + +val min_exn : ('a -> 'a -> int) -> 'a t -> 'a +(** [min_exn cmp a] is like {!min}, but + @raise Invalid_argument if [a] is empty. + @since NEXT_RELEASE *) + +val argmin : ('a -> 'a -> int) -> 'a t -> int option +(** [argmin cmp a] returns [None] if [a] is empty, otherwise, returns [Some i] where [i] + is the index of a minimum element in [a] with respect to [cmp]. + @since NEXT_RELEASE *) + +val argmin_exn : ('a -> 'a -> int) -> 'a t -> int +(** [argmin_exn cmp a] is like {!argmin}, but + @raise Invalid_argument if [a] is empty. + @since NEXT_RELEASE *) + val lookup : cmp:'a ord -> 'a -> 'a t -> int option (** [lookup ~cmp key a] lookups the index of some key [key] in a sorted array [a]. Undefined behavior if the array [a] is not sorted wrt [~cmp]. diff --git a/src/core/CCArrayLabels.mli b/src/core/CCArrayLabels.mli index a6fa09e4..b8725703 100644 --- a/src/core/CCArrayLabels.mli +++ b/src/core/CCArrayLabels.mli @@ -141,6 +141,47 @@ val find_idx : f:('a -> bool) -> 'a t -> (int * 'a) option and [f x] holds. Otherwise returns [None]. @since 0.3.4 *) +val max : cmp:('a -> 'a -> int) -> 'a t -> 'a option +(** [max ~cmp a] returns [None] if [a] is empty, otherwise, returns [Some e] where [e] + is a maximum element in [a] with respect to [cmp]. + @since NEXT_RELEASE *) + +val max_exn : cmp:('a -> 'a -> int) -> 'a t -> 'a +(** [max_exn ~cmp a] is like {!max}, but + @raise Invalid_argument if [a] is empty. + @since NEXT_RELEASE *) + + +val argmax : cmp:('a -> 'a -> int) -> 'a t -> int option +(** [argmax ~cmp a] returns [None] if [a] is empty, otherwise, returns [Some i] where [i] + is the index of a maximum element in [a] with respect to [cmp]. + @since NEXT_RELEASE *) + +val argmax_exn : cmp:('a -> 'a -> int) -> 'a t -> int +(** [argmax_exn ~cmp a] is like {!argmax}, but + @raise Invalid_argument if [a] is empty. + @since NEXT_RELEASE *) + +val min : cmp:('a -> 'a -> int) -> 'a t -> 'a option +(** [min ~cmp a] returns [None] if [a] is empty, otherwise, returns [Some e] where [e] + is a minimum element in [a] with respect to [cmp]. + @since NEXT_RELEASE *) + +val min_exn : cmp:('a -> 'a -> int) -> 'a t -> 'a +(** [min_exn ~cmp a] is like {!min}, but + @raise Invalid_argument if [a] is empty. + @since NEXT_RELEASE *) + +val argmin : cmp:('a -> 'a -> int) -> 'a t -> int option +(** [argmin ~cmp a] returns [None] if [a] is empty, otherwise, returns [Some i] where [i] + is the index of a minimum element in [a] with respect to [cmp]. + @since NEXT_RELEASE *) + +val argmin_exn : cmp:('a -> 'a -> int) -> 'a t -> int +(** [argmin_exn ~cmp a] is like {!argmin}, but + @raise Invalid_argument if [a] is empty. + @since NEXT_RELEASE *) + val lookup : cmp:('a ord[@keep_label]) -> key:'a -> 'a t -> int option (** [lookup ~cmp ~key a] lookups the index of some key [key] in a sorted array [a]. Undefined behavior if the array [a] is not sorted wrt [cmp]. diff --git a/tests/core/t_array.ml b/tests/core/t_array.ml index 30c7d97a..a0c3ab4a 100644 --- a/tests/core/t_array.ml +++ b/tests/core/t_array.ml @@ -140,6 +140,22 @@ t @@ fun () -> rev [| 1; 2 |] = [| 2; 1 |];; t @@ fun () -> rev [||] = [||];; q Q.(array small_int) (fun a -> mem 1 a = Array.mem 1 a);; +eq (Some 3) (max Stdlib.compare [| 1; 2; 3 |]);; +eq (Some 4) (max Stdlib.compare [| 4; -1; 2; 3 |]);; +eq (None) (max Stdlib.compare [||]);; + +eq (Some 2) (argmax Stdlib.compare [| 1; 2; 3 |]);; +eq (Some 0) (argmax Stdlib.compare [| 4; -1; 2; 3 |]);; +eq (None) (argmax Stdlib.compare [||]);; + +eq (Some 1) (min Stdlib.compare [| 1; 2; 3 |]);; +eq (Some ~-1) (min Stdlib.compare [| 4; -1; 2; 3 |]);; +eq (None) (min Stdlib.compare [||]);; + +eq (Some 0) (argmin Stdlib.compare [| 1; 2; 3 |]);; +eq (Some 1) (argmin Stdlib.compare [| 4; -1; 2; 3 |]);; +eq (None) (argmin Stdlib.compare [||]);; + t @@ fun () -> filter_map (fun x ->