mirror of
https://github.com/c-cube/iter.git
synced 2025-12-06 11:15:32 -05:00
Merge branch 'master' into stable for 0.10
This commit is contained in:
commit
047abfe956
10 changed files with 347 additions and 15 deletions
24
CHANGELOG.md
24
CHANGELOG.md
|
|
@ -1,5 +1,29 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.10
|
||||||
|
|
||||||
|
- add `{union,inter,diff,subset}`
|
||||||
|
- add `{join_by,join_all_by,group_join_by}`
|
||||||
|
- add `find_map{,i}` as better alias to existing functions
|
||||||
|
- add `{max_exn,min_exn}`
|
||||||
|
- add `count`
|
||||||
|
- add `doc` and `test` to opam
|
||||||
|
|
||||||
|
## 0.9
|
||||||
|
|
||||||
|
- distinction between `diagonal,diagonal_l`
|
||||||
|
- add `init,fold_map,fold_filter_map,sorted,diagonal,findi,…`
|
||||||
|
- fix a few typos
|
||||||
|
- update readme: convert into asciidoc, add tutorial
|
||||||
|
- remove deprecated functions, add missing links to `SequenceLabels`
|
||||||
|
|
||||||
|
## 0.8
|
||||||
|
|
||||||
|
- loop based implementation for `int_range_by`
|
||||||
|
- move files to 'src/', use qtest for tests
|
||||||
|
- add `int_range_by`
|
||||||
|
- add `Sequence.flat_map_l`
|
||||||
|
|
||||||
## 0.7
|
## 0.7
|
||||||
|
|
||||||
- add missing entry in changelog and missing since annotations
|
- add missing entry in changelog and missing since annotations
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ way of iterating on a finite number of values, only allocating (most of the time
|
||||||
one intermediate closure to do so. For instance, iterating on keys, or values,
|
one intermediate closure to do so. For instance, iterating on keys, or values,
|
||||||
of a `Hashtbl.t`, without creating a list.
|
of a `Hashtbl.t`, without creating a list.
|
||||||
|
|
||||||
|
toc::[]
|
||||||
|
|
||||||
== Documentation
|
== Documentation
|
||||||
|
|
||||||
There is only one important type, `'a Sequence.t`, and lots of functions built
|
There is only one important type, `'a Sequence.t`, and lots of functions built
|
||||||
|
|
@ -93,7 +95,6 @@ underlying hash function):
|
||||||
- : int = 11
|
- : int = 11
|
||||||
|
|
||||||
(* now to get the values *)
|
(* now to get the values *)
|
||||||
# Sequence.of_t
|
|
||||||
# Sequence.of_hashtbl h |> Sequence.map snd |> Sequence.to_list;;
|
# Sequence.of_hashtbl h |> Sequence.map snd |> Sequence.to_list;;
|
||||||
- : string list = ["6"; "2"; "8"; "7"; "3"; "5"; "4"; "9"; "0"; "10"; "1"]
|
- : string list = ["6"; "2"; "8"; "7"; "3"; "5"; "4"; "9"; "0"; "10"; "1"]
|
||||||
----
|
----
|
||||||
|
|
@ -120,7 +121,7 @@ use `Sequence.(--) : int -> int -> int Sequence.t`.
|
||||||
|
|
||||||
NOTE: with **flambda** under sufficiently strong
|
NOTE: with **flambda** under sufficiently strong
|
||||||
optimization flags, such compositions of operators
|
optimization flags, such compositions of operators
|
||||||
will be compiled to an actual loop with no overhead!
|
should be compiled to an actual loop with no overhead!
|
||||||
|
|
||||||
=== Iterating on sub-trees
|
=== Iterating on sub-trees
|
||||||
|
|
||||||
|
|
@ -168,6 +169,7 @@ enumerating the ways we can insert an element in a list.
|
||||||
|
|
||||||
[source,OCaml]
|
[source,OCaml]
|
||||||
----
|
----
|
||||||
|
# open Sequence.Infix;;
|
||||||
# module S = Sequence ;;
|
# module S = Sequence ;;
|
||||||
# let rec insert x l = match l with
|
# let rec insert x l = match l with
|
||||||
| [] -> S.return [x]
|
| [] -> S.return [x]
|
||||||
|
|
|
||||||
2
_oasis
2
_oasis
|
|
@ -1,6 +1,6 @@
|
||||||
OASISFormat: 0.4
|
OASISFormat: 0.4
|
||||||
Name: sequence
|
Name: sequence
|
||||||
Version: 0.9
|
Version: 0.10
|
||||||
Homepage: https://github.com/c-cube/sequence
|
Homepage: https://github.com/c-cube/sequence
|
||||||
Authors: Simon Cruanes
|
Authors: Simon Cruanes
|
||||||
License: BSD-2-clause
|
License: BSD-2-clause
|
||||||
|
|
|
||||||
10
opam
10
opam
|
|
@ -1,6 +1,6 @@
|
||||||
opam-version: "1.2"
|
opam-version: "1.2"
|
||||||
name: "sequence"
|
name: "sequence"
|
||||||
version: "0.9"
|
version: "0.10"
|
||||||
author: "Simon Cruanes"
|
author: "Simon Cruanes"
|
||||||
maintainer: "simon.cruanes@inria.fr"
|
maintainer: "simon.cruanes@inria.fr"
|
||||||
license: "BSD-2-clauses"
|
license: "BSD-2-clauses"
|
||||||
|
|
@ -11,6 +11,14 @@ build: [
|
||||||
]
|
]
|
||||||
[make "build"]
|
[make "build"]
|
||||||
]
|
]
|
||||||
|
build-doc: [
|
||||||
|
["./configure" "--enable-docs"]
|
||||||
|
[make "doc"]
|
||||||
|
]
|
||||||
|
build-test: [
|
||||||
|
["./configure" "--enable-tests"]
|
||||||
|
[make "test"]
|
||||||
|
]
|
||||||
install: [make "install"]
|
install: [make "install"]
|
||||||
remove: [
|
remove: [
|
||||||
["ocamlfind" "remove" "sequence"]
|
["ocamlfind" "remove" "sequence"]
|
||||||
|
|
|
||||||
6
setup.ml
6
setup.ml
|
|
@ -1,7 +1,7 @@
|
||||||
(* setup.ml generated for the first time by OASIS v0.4.4 *)
|
(* setup.ml generated for the first time by OASIS v0.4.4 *)
|
||||||
|
|
||||||
(* OASIS_START *)
|
(* OASIS_START *)
|
||||||
(* DO NOT EDIT (digest: fc3602a8b67872256edf65d37d0266b7) *)
|
(* DO NOT EDIT (digest: b6facd5b08b6b1360edc26bd90d50fa3) *)
|
||||||
(*
|
(*
|
||||||
Regenerated by OASIS v0.4.8
|
Regenerated by OASIS v0.4.8
|
||||||
Visit http://oasis.forge.ocamlcore.org for more information and
|
Visit http://oasis.forge.ocamlcore.org for more information and
|
||||||
|
|
@ -7037,7 +7037,7 @@ let setup_t =
|
||||||
{
|
{
|
||||||
oasis_version = "0.4";
|
oasis_version = "0.4";
|
||||||
ocaml_version = None;
|
ocaml_version = None;
|
||||||
version = "0.9";
|
version = "0.10";
|
||||||
license =
|
license =
|
||||||
OASISLicense.DEP5License
|
OASISLicense.DEP5License
|
||||||
(OASISLicense.DEP5Unit
|
(OASISLicense.DEP5Unit
|
||||||
|
|
@ -8243,7 +8243,7 @@ let setup_t =
|
||||||
};
|
};
|
||||||
oasis_fn = Some "_oasis";
|
oasis_fn = Some "_oasis";
|
||||||
oasis_version = "0.4.8";
|
oasis_version = "0.4.8";
|
||||||
oasis_digest = Some "\198\255:M\202\255\011Hi\149\143\207P\190g\219";
|
oasis_digest = Some "o\181u\130\246\134[37Z-Cy\216\208\151";
|
||||||
oasis_exec = None;
|
oasis_exec = None;
|
||||||
oasis_setup_args = [];
|
oasis_setup_args = [];
|
||||||
setup_update = false
|
setup_update = false
|
||||||
|
|
|
||||||
8
src/META
8
src/META
|
|
@ -1,6 +1,6 @@
|
||||||
# OASIS_START
|
# OASIS_START
|
||||||
# DO NOT EDIT (digest: b247543864e9cc39f327533c7e23c440)
|
# DO NOT EDIT (digest: 47d925b722c4289a923085abbf97bba8)
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "Simple sequence (iterator) datatype and combinators"
|
description = "Simple sequence (iterator) datatype and combinators"
|
||||||
requires = "bytes"
|
requires = "bytes"
|
||||||
archive(byte) = "sequence.cma"
|
archive(byte) = "sequence.cma"
|
||||||
|
|
@ -9,7 +9,7 @@ archive(native) = "sequence.cmxa"
|
||||||
archive(native, plugin) = "sequence.cmxs"
|
archive(native, plugin) = "sequence.cmxs"
|
||||||
exists_if = "sequence.cma"
|
exists_if = "sequence.cma"
|
||||||
package "invert" (
|
package "invert" (
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "Simple sequence (iterator) datatype and combinators"
|
description = "Simple sequence (iterator) datatype and combinators"
|
||||||
requires = "sequence delimcc"
|
requires = "sequence delimcc"
|
||||||
archive(byte) = "invert.cma"
|
archive(byte) = "invert.cma"
|
||||||
|
|
@ -20,7 +20,7 @@ package "invert" (
|
||||||
)
|
)
|
||||||
|
|
||||||
package "bigarray" (
|
package "bigarray" (
|
||||||
version = "0.9"
|
version = "0.10"
|
||||||
description = "Simple sequence (iterator) datatype and combinators"
|
description = "Simple sequence (iterator) datatype and combinators"
|
||||||
requires = "sequence bigarray"
|
requires = "sequence bigarray"
|
||||||
archive(byte) = "bigarray.cma"
|
archive(byte) = "bigarray.cma"
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@ type (+'a, +'b) t2 = ('a -> 'b -> unit) -> unit
|
||||||
let pp_ilist = Q.Print.(list int)
|
let pp_ilist = Q.Print.(list int)
|
||||||
*)
|
*)
|
||||||
|
|
||||||
|
type 'a equal = 'a -> 'a -> bool
|
||||||
|
type 'a hash = 'a -> int
|
||||||
|
|
||||||
(** Build a sequence from a iter function *)
|
(** Build a sequence from a iter function *)
|
||||||
let from_iter f = f
|
let from_iter f = f
|
||||||
|
|
||||||
|
|
@ -411,6 +414,28 @@ let group_by (type k) ?(hash=Hashtbl.hash) ?(eq=(=)) seq =
|
||||||
|> OUnit.assert_equal [[1];[2;2;2];[3;3;3];[4]]
|
|> OUnit.assert_equal [[1];[2;2;2];[3;3;3];[4]]
|
||||||
*)
|
*)
|
||||||
|
|
||||||
|
let count (type k) ?(hash=Hashtbl.hash) ?(eq=(=)) seq =
|
||||||
|
let module Tbl = Hashtbl.Make(struct
|
||||||
|
type t = k
|
||||||
|
let equal = eq
|
||||||
|
let hash = hash
|
||||||
|
end) in
|
||||||
|
(* compute group table *)
|
||||||
|
let tbl = Tbl.create 32 in
|
||||||
|
seq
|
||||||
|
(fun x ->
|
||||||
|
let n = try Tbl.find tbl x with Not_found -> 0 in
|
||||||
|
Tbl.replace tbl x (n+1)
|
||||||
|
);
|
||||||
|
fun yield ->
|
||||||
|
Tbl.iter (fun x n -> yield (x,n)) tbl
|
||||||
|
|
||||||
|
(*$R
|
||||||
|
[1;2;3;3;2;2;3;4]
|
||||||
|
|> of_list |> count ?eq:None ?hash:None |> sort ?cmp:None |> to_list
|
||||||
|
|> OUnit.assert_equal [1,1;2,3;3,3;4,1]
|
||||||
|
*)
|
||||||
|
|
||||||
let uniq ?(eq=fun x y -> x = y) seq k =
|
let uniq ?(eq=fun x y -> x = y) seq k =
|
||||||
let has_prev = ref false
|
let has_prev = ref false
|
||||||
and prev = ref (Obj.magic 0) in (* avoid option type, costly *)
|
and prev = ref (Obj.magic 0) in (* avoid option type, costly *)
|
||||||
|
|
@ -499,6 +524,142 @@ let join ~join_row s1 s2 k =
|
||||||
OUnit.assert_equal ["1 = 1"; "2 = 2"] (to_list s);
|
OUnit.assert_equal ["1 = 1"; "2 = 2"] (to_list s);
|
||||||
*)
|
*)
|
||||||
|
|
||||||
|
let join_by (type a) ?(eq=(=)) ?(hash=Hashtbl.hash) f1 f2 ~merge 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 ->
|
||||||
|
let key = f1 x in
|
||||||
|
Tbl.add tbl key x);
|
||||||
|
let res = ref [] in
|
||||||
|
c2
|
||||||
|
(fun y ->
|
||||||
|
let key = f2 y in
|
||||||
|
let xs = Tbl.find_all tbl key in
|
||||||
|
List.iter
|
||||||
|
(fun x -> match merge key x y with
|
||||||
|
| None -> ()
|
||||||
|
| Some z -> res := z :: !res)
|
||||||
|
xs);
|
||||||
|
fun yield -> List.iter yield !res
|
||||||
|
|
||||||
|
type ('a, 'b) join_all_cell = {
|
||||||
|
mutable ja_left: 'a list;
|
||||||
|
mutable ja_right: 'b list;
|
||||||
|
}
|
||||||
|
|
||||||
|
let join_all_by (type a) ?(eq=(=)) ?(hash=Hashtbl.hash) f1 f2 ~merge 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
|
||||||
|
(* build the map [key -> cell] *)
|
||||||
|
c1
|
||||||
|
(fun x ->
|
||||||
|
let key = f1 x in
|
||||||
|
try
|
||||||
|
let c = Tbl.find tbl key in
|
||||||
|
c.ja_left <- x :: c.ja_left
|
||||||
|
with Not_found ->
|
||||||
|
Tbl.add tbl key {ja_left=[x]; ja_right=[]});
|
||||||
|
c2
|
||||||
|
(fun y ->
|
||||||
|
let key = f2 y in
|
||||||
|
try
|
||||||
|
let c = Tbl.find tbl key in
|
||||||
|
c.ja_right <- y :: c.ja_right
|
||||||
|
with Not_found ->
|
||||||
|
Tbl.add tbl key {ja_left=[]; ja_right=[y]});
|
||||||
|
let res = ref [] in
|
||||||
|
Tbl.iter
|
||||||
|
(fun key cell -> match merge key cell.ja_left cell.ja_right with
|
||||||
|
| None -> ()
|
||||||
|
| Some z -> res := z :: !res)
|
||||||
|
tbl;
|
||||||
|
fun yield -> List.iter yield !res
|
||||||
|
|
||||||
|
let group_join_by (type a) ?(eq=(=)) ?(hash=Hashtbl.hash) f 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 y ->
|
||||||
|
(* project [y] into some element of [c1] *)
|
||||||
|
let key = f y in
|
||||||
|
try
|
||||||
|
let l = Tbl.find tbl key in
|
||||||
|
Tbl.replace tbl key (y :: l)
|
||||||
|
with Not_found -> ());
|
||||||
|
fun yield -> Tbl.iter (fun k l -> yield (k,l)) tbl
|
||||||
|
|
||||||
|
(*$=
|
||||||
|
['a', ["abc"; "attic"]; \
|
||||||
|
'b', ["barbary"; "boom"; "bop"]; \
|
||||||
|
'c', []] \
|
||||||
|
(group_join_by (fun s->s.[0]) \
|
||||||
|
(of_str "abc") \
|
||||||
|
(of_list ["abc"; "boom"; "attic"; "deleted"; "barbary"; "bop"]) \
|
||||||
|
|> map (fun (c,l)->c,List.sort Pervasives.compare l) \
|
||||||
|
|> 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
|
let rec unfoldr f b k = match f b with
|
||||||
| None -> ()
|
| None -> ()
|
||||||
| Some (x, b') ->
|
| Some (x, b') ->
|
||||||
|
|
@ -532,6 +693,10 @@ let max ?(lt=fun x y -> x < y) seq =
|
||||||
| Some y -> if lt y x then ret := Some x);
|
| Some y -> if lt y x then ret := Some x);
|
||||||
!ret
|
!ret
|
||||||
|
|
||||||
|
let max_exn ?lt seq = match max ?lt seq with
|
||||||
|
| Some x -> x
|
||||||
|
| None -> raise Not_found
|
||||||
|
|
||||||
let min ?(lt=fun x y -> x < y) seq =
|
let min ?(lt=fun x y -> x < y) seq =
|
||||||
let ret = ref None in
|
let ret = ref None in
|
||||||
seq
|
seq
|
||||||
|
|
@ -540,6 +705,15 @@ let min ?(lt=fun x y -> x < y) seq =
|
||||||
| Some y -> if lt x y then ret := Some x);
|
| Some y -> if lt x y then ret := Some x);
|
||||||
!ret
|
!ret
|
||||||
|
|
||||||
|
let min_exn ?lt seq = match min ?lt seq with
|
||||||
|
| Some x -> x
|
||||||
|
| None -> raise Not_found
|
||||||
|
|
||||||
|
(*$= & ~printer:string_of_int
|
||||||
|
100 (0 -- 100 |> max_exn ?lt:None)
|
||||||
|
0 (0 -- 100 |> min_exn ?lt:None)
|
||||||
|
*)
|
||||||
|
|
||||||
exception ExitHead
|
exception ExitHead
|
||||||
|
|
||||||
let head seq =
|
let head seq =
|
||||||
|
|
@ -664,7 +838,7 @@ let mem ?(eq=(=)) x seq = exists (eq x) seq
|
||||||
|
|
||||||
exception ExitFind
|
exception ExitFind
|
||||||
|
|
||||||
let find f seq =
|
let find_map f seq =
|
||||||
let r = ref None in
|
let r = ref None in
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
|
|
@ -676,7 +850,9 @@ let find f seq =
|
||||||
end;
|
end;
|
||||||
!r
|
!r
|
||||||
|
|
||||||
let findi f seq =
|
let find = find_map
|
||||||
|
|
||||||
|
let find_mapi f seq =
|
||||||
let i = ref 0 in
|
let i = ref 0 in
|
||||||
let r = ref None in
|
let r = ref None in
|
||||||
begin
|
begin
|
||||||
|
|
@ -689,7 +865,9 @@ let findi f seq =
|
||||||
end;
|
end;
|
||||||
!r
|
!r
|
||||||
|
|
||||||
let find_pred f seq = find (fun x -> if f x then Some x else None) seq
|
let findi = find_mapi
|
||||||
|
|
||||||
|
let find_pred f seq = find_map (fun x -> if f x then Some x else None) seq
|
||||||
|
|
||||||
let find_pred_exn f seq = match find_pred f seq with
|
let find_pred_exn f seq = match find_pred f seq with
|
||||||
| Some x -> x
|
| Some x -> x
|
||||||
|
|
@ -39,6 +39,9 @@ type +'a sequence = 'a t
|
||||||
type (+'a, +'b) t2 = ('a -> 'b -> unit) -> unit
|
type (+'a, +'b) t2 = ('a -> 'b -> unit) -> unit
|
||||||
(** Sequence of pairs of values of type ['a] and ['b]. *)
|
(** Sequence of pairs of values of type ['a] and ['b]. *)
|
||||||
|
|
||||||
|
type 'a equal = 'a -> 'a -> bool
|
||||||
|
type 'a hash = 'a -> int
|
||||||
|
|
||||||
(** {2 Build a sequence} *)
|
(** {2 Build a sequence} *)
|
||||||
|
|
||||||
val from_iter : (('a -> unit) -> unit) -> 'a t
|
val from_iter : (('a -> unit) -> unit) -> 'a t
|
||||||
|
|
@ -144,10 +147,18 @@ val find : ('a -> 'b option) -> 'a t -> 'b option
|
||||||
(** Find the first element on which the function doesn't return [None]
|
(** Find the first element on which the function doesn't return [None]
|
||||||
@since 0.5 *)
|
@since 0.5 *)
|
||||||
|
|
||||||
|
val find_map : ('a -> 'b option) -> 'a t -> 'b option
|
||||||
|
(** Alias to {!find}
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
val findi : (int -> 'a -> 'b option) -> 'a t -> 'b option
|
val findi : (int -> 'a -> 'b option) -> 'a t -> 'b option
|
||||||
(** Indexed version of {!find}
|
(** Indexed version of {!find}
|
||||||
@since 0.9 *)
|
@since 0.9 *)
|
||||||
|
|
||||||
|
val find_mapi : (int -> 'a -> 'b option) -> 'a t -> 'b option
|
||||||
|
(** Alias to {!findi}
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
val find_pred : ('a -> bool) -> 'a t -> 'a option
|
val find_pred : ('a -> bool) -> 'a t -> 'a option
|
||||||
(** [find_pred p l] finds the first element of [l] that satisfies [p],
|
(** [find_pred p l] finds the first element of [l] that satisfies [p],
|
||||||
or returns [None] if no element satisfies [p]
|
or returns [None] if no element satisfies [p]
|
||||||
|
|
@ -241,6 +252,12 @@ val group_by : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) ->
|
||||||
The result sequence is traversable as many times as required.
|
The result sequence is traversable as many times as required.
|
||||||
@since 0.6 *)
|
@since 0.6 *)
|
||||||
|
|
||||||
|
val count : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) ->
|
||||||
|
'a t -> ('a * int) t
|
||||||
|
(** Map each distinct element to its number of occurrences in the whole seq.
|
||||||
|
Similar to [group_by seq |> map (fun l->List.hd l, List.length l)]
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
val uniq : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t
|
val uniq : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t
|
||||||
(** Remove consecutive duplicate elements. Basically this is
|
(** Remove consecutive duplicate elements. Basically this is
|
||||||
like [fun seq -> map List.hd (group seq)]. *)
|
like [fun seq -> map List.hd (group seq)]. *)
|
||||||
|
|
@ -271,6 +288,93 @@ val join : join_row:('a -> 'b -> 'c option) -> 'a t -> 'b t -> 'c t
|
||||||
the two elements do not combine. Assume that [b] allows for multiple
|
the two elements do not combine. Assume that [b] allows for multiple
|
||||||
iterations. *)
|
iterations. *)
|
||||||
|
|
||||||
|
val join_by : ?eq:'key equal -> ?hash:'key hash ->
|
||||||
|
('a -> 'key) -> ('b -> 'key) ->
|
||||||
|
merge:('key -> 'a -> 'b -> 'c option) ->
|
||||||
|
'a t ->
|
||||||
|
'b t ->
|
||||||
|
'c t
|
||||||
|
(** [join key1 key2 ~merge] is a binary operation
|
||||||
|
that takes two sequences [a] and [b], projects their
|
||||||
|
elements resp. with [key1] and [key2], and combine
|
||||||
|
values [(x,y)] from [(a,b)] with the same [key]
|
||||||
|
using [merge]. If [merge] returns [None], the combination
|
||||||
|
of values is discarded.
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
val join_all_by : ?eq:'key equal -> ?hash:'key hash ->
|
||||||
|
('a -> 'key) -> ('b -> 'key) ->
|
||||||
|
merge:('key -> 'a list -> 'b list -> 'c option) ->
|
||||||
|
'a t ->
|
||||||
|
'b t ->
|
||||||
|
'c t
|
||||||
|
(** [join_all_by key1 key2 ~merge] is a binary operation
|
||||||
|
that takes two sequences [a] and [b], projects their
|
||||||
|
elements resp. with [key1] and [key2], and, for each key [k]
|
||||||
|
occurring in at least one of them:
|
||||||
|
- compute the list [l1] of elements of [a] that map to [k]
|
||||||
|
- compute the list [l2] of elements of [b] that map to [k]
|
||||||
|
- call [merge k l1 l2]. If [merge] returns [None], the combination
|
||||||
|
of values is discarded, otherwise it returns [Some c]
|
||||||
|
and [c] is inserted in the result.
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
val group_join_by : ?eq:'a equal -> ?hash:'a hash ->
|
||||||
|
('b -> 'a) ->
|
||||||
|
'a t ->
|
||||||
|
'b t ->
|
||||||
|
('a * 'b list) t
|
||||||
|
(** [group_join_by key2] associates to every element [x] of
|
||||||
|
the first sequence, all the elements [y] of the second
|
||||||
|
sequence such that [eq x (key y)]. Elements of the first
|
||||||
|
sequences without corresponding values in the second one
|
||||||
|
are mapped to [[]]
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
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 0.10 *)
|
||||||
|
|
||||||
|
(*$=
|
||||||
|
[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 0.10 *)
|
||||||
|
|
||||||
|
(*$=
|
||||||
|
[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 0.10 *)
|
||||||
|
|
||||||
|
(*$=
|
||||||
|
[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 0.10 *)
|
||||||
|
|
||||||
|
(*$T
|
||||||
|
subset (2 -- 4) (1 -- 4)
|
||||||
|
not (subset (1 -- 4) (2 -- 10))
|
||||||
|
*)
|
||||||
|
|
||||||
val unfoldr : ('b -> ('a * 'b) option) -> 'b -> 'a t
|
val unfoldr : ('b -> ('a * 'b) option) -> 'b -> 'a t
|
||||||
(** [unfoldr f b] will apply [f] to [b]. If it
|
(** [unfoldr f b] will apply [f] to [b]. If it
|
||||||
yields [Some (x,b')] then [x] is returned
|
yields [Some (x,b')] then [x] is returned
|
||||||
|
|
@ -284,10 +388,20 @@ val max : ?lt:('a -> 'a -> bool) -> 'a t -> 'a option
|
||||||
@return None if the sequence is empty, Some [m] where [m] is the maximal
|
@return None if the sequence is empty, Some [m] where [m] is the maximal
|
||||||
element otherwise *)
|
element otherwise *)
|
||||||
|
|
||||||
|
val max_exn : ?lt:('a -> 'a -> bool) -> 'a t -> 'a
|
||||||
|
(** Unsafe version of {!max}
|
||||||
|
@raise Not_found if the sequence is empty
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
val min : ?lt:('a -> 'a -> bool) -> 'a t -> 'a option
|
val min : ?lt:('a -> 'a -> bool) -> 'a t -> 'a option
|
||||||
(** Min element of the sequence, using the given comparison function.
|
(** Min element of the sequence, using the given comparison function.
|
||||||
see {!max} for more details. *)
|
see {!max} for more details. *)
|
||||||
|
|
||||||
|
val min_exn : ?lt:('a -> 'a -> bool) -> 'a t -> 'a
|
||||||
|
(** Unsafe version of {!min}
|
||||||
|
@raise Not_found if the sequence is empty
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
val head : 'a t -> 'a option
|
val head : 'a t -> 'a option
|
||||||
(** First element, if any, otherwise [None]
|
(** First element, if any, otherwise [None]
|
||||||
@since 0.5.1 *)
|
@since 0.5.1 *)
|
||||||
|
|
@ -1 +1 @@
|
||||||
sequence.ml
|
Sequence.ml
|
||||||
|
|
@ -212,6 +212,12 @@ val group_by : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) ->
|
||||||
The result sequence is traversable as many times as required.
|
The result sequence is traversable as many times as required.
|
||||||
@since 0.6 *)
|
@since 0.6 *)
|
||||||
|
|
||||||
|
val count : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) ->
|
||||||
|
'a t -> ('a * int) t
|
||||||
|
(** Map each distinct element to its number of occurrences in the whole seq.
|
||||||
|
Similar to [group_by seq |> map (fun l->List.hd l, List.length l)]
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
val uniq : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t
|
val uniq : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t
|
||||||
(** Remove consecutive duplicate elements. Basically this is
|
(** Remove consecutive duplicate elements. Basically this is
|
||||||
like [fun seq -> map List.hd (group seq)]. *)
|
like [fun seq -> map List.hd (group seq)]. *)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue