From 40f33f6f969bae0288d6be4fe8e1e7fee36f4b98 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Thu, 2 Feb 2017 22:04:29 +0100 Subject: [PATCH] add `{union,inter,diff,subset}` --- src/Sequence.ml | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/Sequence.mli | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/src/Sequence.ml b/src/Sequence.ml index da7daa8..3bdb9fc 100644 --- a/src/Sequence.ml +++ b/src/Sequence.ml @@ -613,6 +613,52 @@ let group_join_by (type a) ?(eq=(=)) ?(hash=Hashtbl.hash) f c1 c2 = |> sort |> to_list) *) +let union (type a) ?(eq=(=)) ?(hash=Hashtbl.hash) c1 c2 = + let module Tbl = Hashtbl.Make(struct + type t = a let equal = eq let hash = hash end) in + let tbl = Tbl.create 32 in + c1 (fun x -> Tbl.replace tbl x ()); + c2 (fun x -> Tbl.replace tbl x ()); + fun yield -> Tbl.iter (fun x _ -> yield x) tbl + +type inter_status = + | Inter_left + | Inter_both + +let inter (type a) ?(eq=(=)) ?(hash=Hashtbl.hash) c1 c2 = + let module Tbl = Hashtbl.Make(struct + type t = a let equal = eq let hash = hash end) in + let tbl = Tbl.create 32 in + c1 (fun x -> Tbl.replace tbl x Inter_left); + c2 + (fun x -> + try + match Tbl.find tbl x with + | Inter_left -> + Tbl.replace tbl x Inter_both; (* save *) + | Inter_both -> () + with Not_found -> ()); + fun yield -> Tbl.iter (fun x res -> if res=Inter_both then yield x) tbl + +let diff (type a) ?(eq=(=)) ?(hash=Hashtbl.hash) c1 c2 = + let module Tbl = Hashtbl.Make(struct + type t = a let equal = eq let hash = hash end) in + let tbl = Tbl.create 32 in + c2 (fun x -> Tbl.replace tbl x ()); + fun yield -> + c1 (fun x -> if not (Tbl.mem tbl x) then yield x) + +exception Subset_exit + +let subset (type a) ?(eq=(=)) ?(hash=Hashtbl.hash) c1 c2 = + let module Tbl = Hashtbl.Make(struct + type t = a let equal = eq let hash = hash end) in + let tbl = Tbl.create 32 in + c2 (fun x -> Tbl.replace tbl x ()); + try + c1 (fun x -> if not (Tbl.mem tbl x) then raise Subset_exit); + true + with Subset_exit -> false let rec unfoldr f b k = match f b with | None -> () diff --git a/src/Sequence.mli b/src/Sequence.mli index 1d6509a..fb16c81 100644 --- a/src/Sequence.mli +++ b/src/Sequence.mli @@ -331,6 +331,50 @@ val group_join_by : ?eq:'a equal -> ?hash:'a hash -> are mapped to [[]] @since NEXT_RELEASE *) +val inter : + ?eq:'a equal -> ?hash:'a hash -> + 'a t -> 'a t -> 'a t +(** Intersection of two collections. Each element will occur at most once + in the result. Eager. + @since NEXT_RELEASE *) + +(*$= + [2;4;5;6] (inter (1--6) (cons 2 (4--10)) |> sort |> to_list) + [] (inter (0--5) (6--10) |> to_list) +*) + +val union : + ?eq:'a equal -> ?hash:'a hash -> + 'a t -> 'a t -> 'a t +(** Union of two collections. Each element will occur at most once + in the result. Eager. + @since NEXT_RELEASE *) + +(*$= + [2;4;5;6] (union (4--6) (cons 2 (4--5)) |> sort |> to_list) +*) + +val diff : + ?eq:'a equal -> ?hash:'a hash -> + 'a t -> 'a t -> 'a t +(** Set difference. Eager. + @since NEXT_RELEASE *) + +(*$= + [1;2;8;9;10] (diff (1--10) (3--7) |> to_list) +*) + +val subset : + ?eq:'a equal -> ?hash:'a hash -> + 'a t -> 'a t -> bool +(** [subset a b] returns [true] if all elements of [a] belong to [b]. Eager. + @since NEXT_RELEASE *) + +(*$T + subset (2 -- 4) (1 -- 4) + not (subset (1 -- 4) (2 -- 10)) +*) + val unfoldr : ('b -> ('a * 'b) option) -> 'b -> 'a t (** [unfoldr f b] will apply [f] to [b]. If it yields [Some (x,b')] then [x] is returned