mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-07 11:45:31 -05:00
many more functions in CCList
This commit is contained in:
parent
3ccabcd7b0
commit
9a5e6e9558
2 changed files with 330 additions and 27 deletions
254
core/CCList.ml
254
core/CCList.ml
|
|
@ -100,6 +100,23 @@ let flatten l = flat_map (fun l -> l) l
|
|||
let product f l1 l2 =
|
||||
flat_map (fun x -> map (fun y -> f x y) l2) l1
|
||||
|
||||
let fold_product f acc l1 l2 =
|
||||
List.fold_left
|
||||
(fun acc x1 ->
|
||||
List.fold_left
|
||||
(fun acc x2 -> f acc x1 x2)
|
||||
acc l2
|
||||
) acc l1
|
||||
|
||||
let diagonal l =
|
||||
let rec gen acc l = match l with
|
||||
| [] -> acc
|
||||
| x::l' ->
|
||||
let acc = List.fold_left (fun acc y -> (x,y) :: acc) acc l' in
|
||||
gen acc l'
|
||||
in
|
||||
gen [] l
|
||||
|
||||
let return x = [x]
|
||||
|
||||
let (>>=) l f = flat_map f l
|
||||
|
|
@ -108,31 +125,23 @@ let (<$>) = map
|
|||
|
||||
let (<*>) funs l = product (fun f x -> f x) funs l
|
||||
|
||||
let sorted_merge ?(cmp=Pervasives.compare) l1 l2 =
|
||||
let rec recurse cmp acc l1 l2 = match l1,l2 with
|
||||
| [], _ -> List.rev_append acc l2
|
||||
| _, [] -> List.rev_append acc l1
|
||||
| x1::l1', x2::l2' ->
|
||||
let c = cmp x1 x2 in
|
||||
if c < 0 then recurse cmp (x1::acc) l1' l2
|
||||
else if c > 0 then recurse cmp (x2::acc) l1 l2'
|
||||
else recurse cmp (x1::x2::acc) l1' l2'
|
||||
in
|
||||
recurse cmp [] l1 l2
|
||||
|
||||
(*$T
|
||||
List.sort Pervasives.compare ([(( * )2); ((+)1)] <*> [10;100]) \
|
||||
= [11; 20; 101; 200]
|
||||
*)
|
||||
|
||||
let range i j =
|
||||
let rec up i j acc =
|
||||
if i=j then i::acc else up i (j-1) (j::acc)
|
||||
and down i j acc =
|
||||
if i=j then i::acc else down i (j+1) (j::acc)
|
||||
in
|
||||
if i<=j then up i j [] else down i j []
|
||||
|
||||
(*$T
|
||||
range 0 5 = [0;1;2;3;4;5]
|
||||
range 0 0 = [0]
|
||||
range 5 2 = [5;4;3;2]
|
||||
*)
|
||||
|
||||
let (--) = range
|
||||
|
||||
(*$T
|
||||
append (range 0 100) (range 101 1000) = range 0 1000
|
||||
append (range 1000 500) (range 499 0) = range 1000 0
|
||||
*)
|
||||
|
||||
let take n l =
|
||||
let rec direct i n l = match l with
|
||||
|
|
@ -164,6 +173,211 @@ let last n l =
|
|||
let len = List.length l in
|
||||
if len < n then l else drop (len-n) l
|
||||
|
||||
let find p l =
|
||||
let rec search i l = match l with
|
||||
| [] -> None
|
||||
| x::_ when p x -> Some (i, x)
|
||||
| _::xs -> search (i+1) xs
|
||||
in search 0 l
|
||||
|
||||
let filter_map f l =
|
||||
let rec recurse acc l = match l with
|
||||
| [] -> List.rev acc
|
||||
| x::l' ->
|
||||
let acc' = match f x with | None -> acc | Some y -> y::acc in
|
||||
recurse acc' l'
|
||||
in recurse [] l
|
||||
|
||||
module Set = struct
|
||||
let mem ?(eq=(=)) x l =
|
||||
let rec search eq x l = match l with
|
||||
| [] -> false
|
||||
| y::l' -> eq x y || search eq x l'
|
||||
in search eq x l
|
||||
|
||||
let subset ?(eq=(=)) l1 l2 =
|
||||
List.for_all
|
||||
(fun t -> mem ~eq t l2)
|
||||
l1
|
||||
|
||||
let rec uniq ?(eq=(=)) l = match l with
|
||||
| [] -> []
|
||||
| x::xs when List.exists (eq x) xs -> uniq ~eq xs
|
||||
| x::xs -> x :: uniq ~eq xs
|
||||
|
||||
let rec union ?(eq=(=)) l1 l2 = match l1 with
|
||||
| [] -> l2
|
||||
| x::xs when mem ~eq x l2 -> union ~eq xs l2
|
||||
| x::xs -> x::(union ~eq xs l2)
|
||||
|
||||
let rec inter ?(eq=(=)) l1 l2 = match l1 with
|
||||
| [] -> []
|
||||
| x::xs when mem ~eq x l2 -> x::(inter ~eq xs l2)
|
||||
| _::xs -> inter ~eq xs l2
|
||||
end
|
||||
|
||||
module Idx = struct
|
||||
let mapi f l =
|
||||
let r = ref 0 in
|
||||
map
|
||||
(fun x ->
|
||||
let y = f !r x in
|
||||
incr r; y
|
||||
) l
|
||||
|
||||
(*$T
|
||||
Idx.mapi (fun i x -> i*x) [10;10;10] = [0;10;20]
|
||||
*)
|
||||
|
||||
let iteri f l =
|
||||
let rec aux f i l = match l with
|
||||
| [] -> ()
|
||||
| x::l' -> f i x; aux f (i+1) l'
|
||||
in aux f 0 l
|
||||
|
||||
let foldi f acc l =
|
||||
let rec foldi f acc i l = match l with
|
||||
| [] -> acc
|
||||
| x::l' ->
|
||||
let acc = f acc i x in
|
||||
foldi f acc (i+1) l'
|
||||
in
|
||||
foldi f acc 0 l
|
||||
|
||||
let rec get_exn l i = match l with
|
||||
| [] -> raise Not_found
|
||||
| x::_ when i=0 -> x
|
||||
| _::l' -> get_exn l' (i-1)
|
||||
|
||||
let get l i =
|
||||
try Some (get_exn l i)
|
||||
with Not_found -> None
|
||||
|
||||
(*$T
|
||||
Idx.get (range 0 10) 0 = Some 0
|
||||
Idx.get (range 0 10) 5 = Some 5
|
||||
Idx.get (range 0 10) 11 = None
|
||||
Idx.get [] 0 = None
|
||||
*)
|
||||
|
||||
let set l0 i x =
|
||||
let rec aux l acc i = match l with
|
||||
| [] -> l0
|
||||
| _::l' when i=0 -> List.rev_append acc (x::l')
|
||||
| y::l' ->
|
||||
aux l' (y::acc) (i-1)
|
||||
in
|
||||
aux l0 [] i
|
||||
|
||||
(*$T
|
||||
Idx.set [1;2;3] 0 10 = [10;2;3]
|
||||
Idx.set [1;2;3] 4 10 = [1;2;3]
|
||||
Idx.set [1;2;3] 1 10 = [1;10;3]
|
||||
*)
|
||||
|
||||
let insert l i x =
|
||||
let rec aux l acc i x = match l with
|
||||
| [] -> List.rev_append acc [x]
|
||||
| y::l' when i=0 -> List.rev_append acc (x::y::l')
|
||||
| y::l' ->
|
||||
aux l' (y::acc) (i-1) x
|
||||
in
|
||||
aux l [] i x
|
||||
|
||||
(*$T
|
||||
Idx.insert [1;2;3] 0 10 = [10;1;2;3]
|
||||
Idx.insert [1;2;3] 4 10 = [1;2;3;10]
|
||||
Idx.insert [1;2;3] 1 10 = [1;10;2;3]
|
||||
*)
|
||||
|
||||
let rec remove l0 i =
|
||||
let rec aux l acc i = match l with
|
||||
| [] -> l0
|
||||
| _::l' when i=0 -> List.rev_append acc l'
|
||||
| y::l' ->
|
||||
aux l' (y::acc) (i-1)
|
||||
in
|
||||
aux l0 [] i
|
||||
|
||||
(*$T
|
||||
Idx.remove [1;2;3;4] 0 = [2;3;4]
|
||||
Idx.remove [1;2;3;4] 3 = [1;2;3]
|
||||
Idx.remove [1;2;3;4] 5 = [1;2;3;4]
|
||||
*)
|
||||
end
|
||||
|
||||
let range i j =
|
||||
let rec up i j acc =
|
||||
if i=j then i::acc else up i (j-1) (j::acc)
|
||||
and down i j acc =
|
||||
if i=j then i::acc else down i (j+1) (j::acc)
|
||||
in
|
||||
if i<=j then up i j [] else down i j []
|
||||
|
||||
(*$T
|
||||
range 0 5 = [0;1;2;3;4;5]
|
||||
range 0 0 = [0]
|
||||
range 5 2 = [5;4;3;2]
|
||||
*)
|
||||
|
||||
let (--) = range
|
||||
|
||||
(*$T
|
||||
append (range 0 100) (range 101 1000) = range 0 1000
|
||||
append (range 1000 500) (range 499 0) = range 1000 0
|
||||
*)
|
||||
|
||||
let replicate i x =
|
||||
let rec aux acc i =
|
||||
if i = 0 then acc
|
||||
else aux (x::acc) (i-1)
|
||||
in aux [] i
|
||||
|
||||
let repeat i l =
|
||||
let l' = List.rev l in
|
||||
let rec aux acc i =
|
||||
if i = 0 then List.rev acc
|
||||
else aux (List.rev_append l' acc) (i-1)
|
||||
in aux [] i
|
||||
|
||||
module Assoc = struct
|
||||
type ('a, 'b) t = ('a*'b) list
|
||||
|
||||
let get_exn ?(eq=(=)) l x =
|
||||
let rec search eq l x = match l with
|
||||
| [] -> raise Not_found
|
||||
| (y,z)::l' ->
|
||||
if eq x y then z else search eq l' x
|
||||
in search eq l x
|
||||
|
||||
let get ?eq l x =
|
||||
try Some (get_exn ?eq l x)
|
||||
with Not_found -> None
|
||||
|
||||
(*$T
|
||||
Assoc.get [1, "1"; 2, "2"] 1 = Some "1"
|
||||
Assoc.get [1, "1"; 2, "2"] 2 = Some "2"
|
||||
Assoc.get [1, "1"; 2, "2"] 3 = None
|
||||
Assoc.get [] 42 = None
|
||||
*)
|
||||
|
||||
let set ?(eq=(=)) l x y =
|
||||
let rec search eq acc l x y = match l with
|
||||
| [] -> (x,y)::acc
|
||||
| (x',y')::l' ->
|
||||
if eq x x'
|
||||
then (x,y)::List.rev_append acc l'
|
||||
else search eq ((x',y')::acc) l' x y
|
||||
in search eq [] l x y
|
||||
|
||||
(*$T
|
||||
Assoc.set [1,"1"; 2, "2"] 2 "two" |> List.sort Pervasives.compare \
|
||||
= [1, "1"; 2, "two"]
|
||||
Assoc.set [1,"1"; 2, "2"] 3 "3" |> List.sort Pervasives.compare \
|
||||
= [1, "1"; 2, "2"; 3, "3"]
|
||||
*)
|
||||
end
|
||||
|
||||
(** {2 Conversions} *)
|
||||
|
||||
type 'a sequence = ('a -> unit) -> unit
|
||||
|
|
|
|||
103
core/CCList.mli
103
core/CCList.mli
|
|
@ -49,6 +49,13 @@ val flatten : 'a t t -> 'a t
|
|||
val product : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
|
||||
(** cartesian product of the two lists, with the given combinator *)
|
||||
|
||||
val fold_product : ('c -> 'a -> 'b -> 'c) -> 'c -> 'a t -> 'b t -> 'c
|
||||
(** Fold on the cartesian product *)
|
||||
|
||||
val diagonal : 'a t -> ('a * 'a) t
|
||||
(** All pairs of distinct positions of the list. [list_diagonal l] will
|
||||
return the list of [List.nth i l, List.nth j l] if [i < j]. *)
|
||||
|
||||
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
|
||||
|
||||
val (<$>) : ('a -> 'b) -> 'a t -> 'b t
|
||||
|
|
@ -57,13 +64,6 @@ val return : 'a -> 'a t
|
|||
|
||||
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
|
||||
|
||||
val range : int -> int -> int t
|
||||
(** [range i j] iterates on integers from [i] to [j] included. It works
|
||||
both for decreasing and increasing ranges *)
|
||||
|
||||
val (--) : int -> int -> int t
|
||||
(** Infix alias for [range] *)
|
||||
|
||||
val take : int -> 'a t -> 'a t
|
||||
(** take the [n] first elements, drop the rest *)
|
||||
|
||||
|
|
@ -78,6 +78,95 @@ val last : int -> 'a t -> 'a t
|
|||
(** [last n l] takes the last [n] elements of [l] (or less if
|
||||
[l] doesn't have that many elements *)
|
||||
|
||||
val find : ('a -> bool) -> 'a t -> (int * 'a) option
|
||||
(** [find p x] returns [Some (i,x)] where [x] is the [i]-th element of [l],
|
||||
and [p x] holds. Otherwise returns [None] *)
|
||||
|
||||
val filter_map : ('a -> 'b option) -> 'a t -> 'b t
|
||||
(** Map and remove elements at the same time *)
|
||||
|
||||
val sorted_merge : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
|
||||
(** merges elements from both sorted list, removing duplicates *)
|
||||
|
||||
(** {2 Indices} *)
|
||||
|
||||
module Idx : sig
|
||||
val mapi : (int -> 'a -> 'b) -> 'a t -> 'b t
|
||||
|
||||
val iteri : (int -> 'a -> unit) -> 'a t -> unit
|
||||
|
||||
val foldi : ('b -> int -> 'a -> 'b) -> 'b -> 'a t -> 'b
|
||||
(** fold on list, with index *)
|
||||
|
||||
val get : 'a t -> int -> 'a option
|
||||
|
||||
val get_exn : 'a t -> int -> 'a
|
||||
(** get the i-th element, or
|
||||
@raise Not_found if the index is invalid *)
|
||||
|
||||
val set : 'a t -> int -> 'a -> 'a t
|
||||
(** set i-th element (removes the old one), or does nothing if
|
||||
index too high *)
|
||||
|
||||
val insert : 'a t -> int -> 'a -> 'a t
|
||||
(** insert at i-th position, between the two existing elements. If the
|
||||
index is too high, append at the end of the list *)
|
||||
|
||||
val remove : 'a t -> int -> 'a t
|
||||
(** Remove element at given index. Does nothing if the index is
|
||||
too high. *)
|
||||
end
|
||||
|
||||
(** {2 Set Operators} *)
|
||||
|
||||
module Set : sig
|
||||
val mem : ?eq:('a -> 'a -> bool) -> 'a -> 'a t -> bool
|
||||
(** membership to the list *)
|
||||
|
||||
val subset : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t -> bool
|
||||
(** test for inclusion *)
|
||||
|
||||
val uniq : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t
|
||||
(** list uniq: remove duplicates w.r.t the equality predicate *)
|
||||
|
||||
val union : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t -> 'a t
|
||||
(** list union *)
|
||||
|
||||
val inter : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t -> 'a t
|
||||
(** list intersection *)
|
||||
end
|
||||
|
||||
(** {2 Other Constructors} *)
|
||||
|
||||
val range : int -> int -> int t
|
||||
(** [range i j] iterates on integers from [i] to [j] included. It works
|
||||
both for decreasing and increasing ranges *)
|
||||
|
||||
val (--) : int -> int -> int t
|
||||
(** Infix alias for [range] *)
|
||||
|
||||
val replicate : int -> 'a -> 'a t
|
||||
(** replicate the given element [n] times *)
|
||||
|
||||
val repeat : int -> 'a t -> 'a t
|
||||
(** concatenate the list with itself [n] times *)
|
||||
|
||||
(** {2 Association Lists} *)
|
||||
|
||||
module Assoc : sig
|
||||
type ('a, 'b) t = ('a*'b) list
|
||||
|
||||
val get : ?eq:('a->'a->bool) -> ('a,'b) t -> 'a -> 'b option
|
||||
(** Find the element *)
|
||||
|
||||
val get_exn : ?eq:('a->'a->bool) -> ('a,'b) t -> 'a -> 'b
|
||||
(** Same as [get]
|
||||
@raise Not_found if the element is not present *)
|
||||
|
||||
val set : ?eq:('a->'a->bool) -> ('a,'b) t -> 'a -> 'b -> ('a,'b) t
|
||||
(** Add the binding into the list (erase it if already present) *)
|
||||
end
|
||||
|
||||
(** {2 Conversions} *)
|
||||
|
||||
type 'a sequence = ('a -> unit) -> unit
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue