add CCArray.{sorted,sort_indices,sort_ranking} (closes #81)

This commit is contained in:
Simon Cruanes 2016-10-19 18:17:40 +02:00
parent bc7967054f
commit 2a872907a1
2 changed files with 162 additions and 0 deletions

View file

@ -51,6 +51,29 @@ module type S = sig
val reverse_in_place : 'a t -> unit
(** Reverse the array in place *)
val sorted : ('a -> 'a -> int) -> 'a t -> 'a array
(** [sorted cmp a] makes a copy of [a] and sorts it with [cmp].
@since NEXT_RELEASE *)
val sort_indices : ('a -> 'a -> int) -> 'a t -> int array
(** [sort_indices cmp a] returns a new array [b], with the same length as [a],
such that [b.(i)] is the index of the [i]-th element in [sort cmp a].
In other words, [map (fun i -> a.(i)) (sort_indices a) = sorted cmp a].
[a] is not modified.
@since NEXT_RELEASE *)
val sort_ranking : ('a -> 'a -> int) -> 'a t -> int array
(** [sort_ranking cmp a] returns a new array [b], with the same length as [a],
such that [b.(i)] is the position in [sorted cmp a] of the [i]-th
element of [a].
[a] is not modified.
In other words, [map (fun i -> (sorted cmp a).(i)) (sort_ranking cmp a) = a].
Without duplicates, we also have
[lookup_exn (sorted a) a.(i) = (sorted_ranking a).(i)]
@since NEXT_RELEASE *)
val find : ('a -> 'b option) -> 'a t -> 'b option
(** [find f a] returns [Some y] if there is an element [x] such
that [f x = Some y], else it returns [None] *)
@ -260,6 +283,18 @@ let _shuffle _rand_int a i j =
let b = Array.copy a in shuffle_with st a; a <> b
*)
let _sort_indices cmp a i j =
let len = j-i in
let b = Array.init len (fun k->k) in
Array.sort (fun k1 k2 -> cmp a.(k1+i) a.(k2+i)) b;
b
let _sorted cmp a i j =
let len = j-i in
let b = Array.sub a i len in
Array.sort cmp b;
b
let _choose a i j st =
if i>=j then raise Not_found;
a.(i+Random.State.int st (j-i))
@ -366,6 +401,48 @@ let reverse_in_place a =
a = [| 6;5;4;3;2;1 |]
*)
let sorted cmp a = _sorted cmp a 0 (Array.length a)
(*$= & ~cmp:(=) ~printer:Q.Print.(array int)
[||] (sorted Pervasives.compare [||])
[|0;1;2;3;4|] (sorted Pervasives.compare [|3;2;1;4;0|])
*)
(*$Q
Q.(array int) (fun a -> \
let b = Array.copy a in \
Array.sort Pervasives.compare b; b = sorted Pervasives.compare a)
*)
let sort_indices cmp a = _sort_indices cmp a 0 (Array.length a)
(*$= & ~cmp:(=) ~printer:Q.Print.(array int)
[||] (sort_indices Pervasives.compare [||])
[|4;2;1;0;3|] (sort_indices Pervasives.compare [|"d";"c";"b";"e";"a"|])
*)
(*$Q
Q.(array printable_string) (fun a -> \
let b = sort_indices String.compare a in \
sorted String.compare a = Array.map (Array.get a) b)
*)
let sort_ranking cmp a =
let cmp_int : int -> int -> int = Pervasives.compare in
sort_indices cmp_int (sort_indices cmp a)
(*$= & ~cmp:(=) ~printer:Q.Print.(array int)
[||] (sort_ranking Pervasives.compare [||])
[|3;2;1;4;0|] (sort_ranking Pervasives.compare [|"d";"c";"b";"e";"a"|])
*)
(*$Q
Q.(array printable_string) (fun a -> \
let b = sort_ranking String.compare a in \
let a_sorted = sorted String.compare a in \
a = Array.map (Array.get a_sorted) b)
*)
let rev a =
let b = Array.copy a in
reverse_in_place b;
@ -689,6 +766,68 @@ module Sub = struct
Sub.reverse_in_place s; a = [| 1; 2; 5; 4; 3; 6 |]
*)
let sorted cmp a = _sorted cmp a.arr a.i a.j
(*$= & ~cmp:(=) ~printer:Q.Print.(array int)
[||] \
(let a = 1--6 in let s = Sub.make a 2 ~len:0 in \
Sub.sorted Pervasives.compare s)
[|2;3;4|] \
(let a = [|6;5;4;3;2;1|] in let s = Sub.make a 2 ~len:3 in \
Sub.sorted Pervasives.compare s)
*)
(*$Q
Q.(array int) (fun a -> \
Array.length a > 10 ==> ( Array.length a > 10 && \
let s = Sub.make a 5 ~len:5 in \
let b = Array.sub a 5 5 in \
Array.sort Pervasives.compare b; b = Sub.sorted Pervasives.compare s))
*)
let sort_ranking cmp a =
let idx = _sort_indices cmp a.arr a.i a.j in
let cmp_int : int -> int -> int = Pervasives.compare in
sort_indices cmp_int idx
(*$= & ~cmp:(=) ~printer:Q.Print.(array int)
[||] \
(let a = 1--6 in let s = Sub.make a 2 ~len:0 in \
Sub.sort_ranking Pervasives.compare s)
[|2;1;3;0|] \
(let a = [|"d";"c";"b";"e";"a"|] in let s = Sub.make a 1 ~len:4 in \
Sub.sort_ranking Pervasives.compare s)
*)
(*$Q
Q.(array printable_string) (fun a -> \
Array.length a > 10 ==> ( Array.length a > 10 && \
let s = Sub.make a 5 ~len:5 in \
let b = Sub.sort_indices String.compare s in \
Sub.sorted String.compare s = Array.map (Sub.get s) b))
*)
let sort_indices cmp a = _sort_indices cmp a.arr a.i a.j
(*$= & ~cmp:(=) ~printer:Q.Print.(array int)
[||] \
(let a = 1--6 in let s = Sub.make a 2 ~len:0 in \
Sub.sort_indices Pervasives.compare s)
[|3;1;0;2|] \
(let a = [|"d";"c";"b";"e";"a"|] in let s = Sub.make a 1 ~len:4 in \
Sub.sort_indices Pervasives.compare s)
*)
(*$Q
Q.(array printable_string) (fun a -> \
Array.length a > 10 ==> ( Array.length a > 10 && \
let s = Sub.make a 5 ~len:5 in \
let b = Sub.sort_ranking String.compare s in \
let a_sorted = Sub.sorted String.compare s in \
Sub.copy s = Array.map (Array.get a_sorted) b))
*)
let find f a = _find (fun _ -> f) a.arr a.i a.j
let findi f a = _find (fun i -> f (i-a.i)) a.arr a.i a.j

View file

@ -53,6 +53,29 @@ module type S = sig
val reverse_in_place : 'a t -> unit
(** Reverse the array in place *)
val sorted : ('a -> 'a -> int) -> 'a t -> 'a array
(** [sorted cmp a] makes a copy of [a] and sorts it with [cmp].
@since NEXT_RELEASE *)
val sort_indices : ('a -> 'a -> int) -> 'a t -> int array
(** [sort_indices cmp a] returns a new array [b], with the same length as [a],
such that [b.(i)] is the index of the [i]-th element in [sort cmp a].
In other words, [map (fun i -> a.(i)) (sort_indices a) = sorted cmp a].
[a] is not modified.
@since NEXT_RELEASE *)
val sort_ranking : ('a -> 'a -> int) -> 'a t -> int array
(** [sort_ranking cmp a] returns a new array [b], with the same length as [a],
such that [b.(i)] is the position in [sorted cmp a] of the [i]-th
element of [a].
[a] is not modified.
In other words, [map (fun i -> (sorted cmp a).(i)) (sort_ranking cmp a) = a].
Without duplicates, we also have
[lookup_exn a.(i) (sorted a) = (sorted_ranking a).(i)]
@since NEXT_RELEASE *)
val find : ('a -> 'b option) -> 'a t -> 'b option
(** [find f a] returns [Some y] if there is an element [x] such
that [f x = Some y], else it returns [None] *)