Module Belt.Map
The top level provides generic immutable map operations.
It also has three specialized inner modules Belt.Map.Int, Belt.Map.String and
Belt.Map.Dict: This module separates data from function which is more verbose but slightly more efficient
A immutable sorted map module which allows customize compare behavior.
The implementation uses balanced binary trees, and therefore searching and insertion take time logarithmic in the size of the map.
For more info on this module's usage of identity, `make` and others, please see the top level documentation of Belt, A special encoding for collection safety.
Example usage:
module PairComparator = Belt.Id.MakeComparable(struct
type t = int * int
let cmp (a0, a1) (b0, b1) =
match Pervasives.compare a0 b0 with
| 0 -> Pervasives.compare a1 b1
| c -> c
end)
let myMap = Belt.Map.make ~id:(module PairComparator)
let myMap2 = Belt.Map.set myMap (1, 2) "myValue"module PairComparator =
Belt.Id.MakeComparable({
type t = (int, int);
let cmp = ((a0, a1), (b0, b1)) =>
switch (Pervasives.compare(a0, b0)) {
| 0 => Pervasives.compare(a1, b1)
| c => c
};
});
let myMap = Belt.Map.make(~id=(module PairComparator));
let myMap2 = Belt.Map.set(myMap, (1, 2), "myValue");The API documentation below will assume a predeclared comparator module for integers, IntCmp
module Int : sig ... endmodule Int: { ... };Specalized when key type is int, more efficient than the generic type, its compare behavior is fixed using the built-in comparison
module String : sig ... endmodule String: { ... };specalized when key type is string, more efficient than the generic type, its compare behavior is fixed using the built-in comparison
module Dict : sig ... endmodule Dict: { ... };This module seprate identity from data, it is a bit more verboe but slightly more efficient due to the fact that there is no need to pack identity and data back after each operation
type ('key, 'value, 'identity) ttype t('key, 'value, 'identity);('key, 'identity) tt('key, 'identity)
'key is the field type
'value is the element type
'identity the identity of the collection
type ('key, 'id) id =
(module Belt__.Belt_Id.Comparable
with type identity = 'id
and type t = 'key)type id('key, 'id) =
(module Belt__.Belt_Id.Comparable
with type identity = 'id
and type t = 'key);The identity needed for making an empty map
val make : id:('k, 'id) id -> ('k, 'v, 'id) tlet make: id:id('k, 'id) => t('k, 'v, 'id);make ~id creates a new map by taking in the comparator
let m = Belt.Map.make ~id:(module IntCmp)let m = Belt.Map.make(~id=(module IntCmp));val isEmpty : (_, _, _) t -> boollet isEmpty: t(_, _, _) => bool;isEmpty m checks whether a map m is empty
isEmpty (fromArray [|1,"1"|] ~id:(module IntCmp)) = falseisEmpty(fromArray([|(1, "1")|], ~id=(module IntCmp))) == false;val has : ('k, 'v, 'id) t -> 'k -> boollet has: t('k, 'v, 'id) => 'k => bool;has m k checks whether m has the key k
has (fromArray [|1,"1"|] ~id:(module IntCmp)) 1 = truehas(fromArray([|(1, "1")|], ~id=(module IntCmp)), 1) == true;val cmpU :
('k, 'v, 'id) t ->
('k, 'v, 'id) t ->
('v -> 'v -> int) Js.Fn.arity2 ->
intlet cmpU:
t('k, 'v, 'id) =>
t('k, 'v, 'id) =>
Js.Fn.arity2(('v => 'v => int)) =>
int;val cmp : ('k, 'v, 'id) t -> ('k, 'v, 'id) t -> ('v -> 'v -> int) -> intlet cmp: t('k, 'v, 'id) => t('k, 'v, 'id) => ('v => 'v => int) => int;cmp m0 m1 vcmp
Total ordering of map given total ordering of value function.
It will compare size first and each element following the order one by one.
val eqU :
('k, 'v, 'id) t ->
('k, 'v, 'id) t ->
('v -> 'v -> bool) Js.Fn.arity2 ->
boollet eqU:
t('k, 'v, 'id) =>
t('k, 'v, 'id) =>
Js.Fn.arity2(('v => 'v => bool)) =>
bool;val eq : ('k, 'v, 'id) t -> ('k, 'v, 'id) t -> ('v -> 'v -> bool) -> boollet eq: t('k, 'v, 'id) => t('k, 'v, 'id) => ('v => 'v => bool) => bool;eq m1 m2 veq tests whether the maps m1 and m2 are equal, that is, contain equal keys and associate them with equal data. veq is the equality predicate used to compare the data associated with the keys.
val findFirstByU :
('k, 'v, 'id) t ->
('k -> 'v -> bool) Js.Fn.arity2 ->
('k * 'v) optionlet findFirstByU:
t('k, 'v, 'id) =>
Js.Fn.arity2(('k => 'v => bool)) =>
option(('k, 'v));val findFirstBy : ('k, 'v, 'id) t -> ('k -> 'v -> bool) -> ('k * 'v) optionlet findFirstBy: t('k, 'v, 'id) => ('k => 'v => bool) => option(('k, 'v));findFirstBy m p uses funcion f to find the first key value pair to match predicate p.
let s0 = fromArray ~id:(module IntCmp) [|4,"4";1,"1";2,"2,"3""|];;
findFirstBy s0 (fun k v -> k = 4 ) = option (4, "4");;let s0 =
fromArray(
~id=(module IntCmp),
[|(4, "4"), (1, "1"), (2, "2,"(3, ""))|],
);
findFirstBy(s0, (k, v) => k == 4) == option((4, "4"));val forEachU : ('k, 'v, 'id) t -> ('k -> 'v -> unit) Js.Fn.arity2 -> unitlet forEachU: t('k, 'v, 'id) => Js.Fn.arity2(('k => 'v => unit)) => unit;val forEach : ('k, 'v, 'id) t -> ('k -> 'v -> unit) -> unitlet forEach: t('k, 'v, 'id) => ('k => 'v => unit) => unit;forEach m f applies f to all bindings in map m. f receives the 'k as first argument, and the associated value as second argument. The bindings are passed to f in increasing order with respect to the ordering over the type of the keys.
let s0 = fromArray ~id:(module IntCmp) [|4,"4";1,"1";2,"2,"3""|];;
let acc = ref [] ;;
forEach s0 (fun k v -> acc := (k,v) :: !acc);;
!acc = [4,"4"; 3,"3"; 2,"2"; 1,"1"]let s0 =
fromArray(
~id=(module IntCmp),
[|(4, "4"), (1, "1"), (2, "2,"(3, ""))|],
);
let acc = ref([]);
forEach(s0, (k, v) => acc := [(k, v), ...acc^]);
acc^ == [(4, "4"), (3, "3"), (2, "2"), (1, "1")];val reduceU :
('k, 'v, 'id) t ->
'acc ->
('acc -> 'k -> 'v -> 'acc) Js.Fn.arity3 ->
'acclet reduceU:
t('k, 'v, 'id) =>
'acc =>
Js.Fn.arity3(('acc => 'k => 'v => 'acc)) =>
'acc;val reduce : ('k, 'v, 'id) t -> 'acc -> ('acc -> 'k -> 'v -> 'acc) -> 'acclet reduce: t('k, 'v, 'id) => 'acc => ('acc => 'k => 'v => 'acc) => 'acc;reduce m a f computes (f kN dN ... (f k1 d1 a)...), where k1 ... kN are the keys of all bindings in m (in increasing order), and d1 ... dN are the associated data.
let s0 = fromArray ~id:(module IntCmp) [|4,"4";1,"1";2,"2,"3""|];;
reduce s0 [] (fun acc k v -> (k,v) acc ) = [4,"4";3,"3";2,"2";1,"1"];;let s0 =
fromArray(
~id=(module IntCmp),
[|(4, "4"), (1, "1"), (2, "2,"(3, ""))|],
);
reduce(s0, [], (acc, k, v) => (k, v)(acc))
== [(4, "4"), (3, "3"), (2, "2"), (1, "1")];val everyU : ('k, 'v, 'id) t -> ('k -> 'v -> bool) Js.Fn.arity2 -> boollet everyU: t('k, 'v, 'id) => Js.Fn.arity2(('k => 'v => bool)) => bool;val every : ('k, 'v, 'id) t -> ('k -> 'v -> bool) -> boollet every: t('k, 'v, 'id) => ('k => 'v => bool) => bool;every m p checks if all the bindings of the map satisfy the predicate p. Order unspecified
val someU : ('k, 'v, 'id) t -> ('k -> 'v -> bool) Js.Fn.arity2 -> boollet someU: t('k, 'v, 'id) => Js.Fn.arity2(('k => 'v => bool)) => bool;val some : ('k, 'v, 'id) t -> ('k -> 'v -> bool) -> boollet some: t('k, 'v, 'id) => ('k => 'v => bool) => bool;some m p checks if at least one binding of the map satisfy the predicate p. Order unspecified
val size : ('k, 'v, 'id) t -> intlet size: t('k, 'v, 'id) => int;size s
size (fromArray [2,"2"; 2,"1"; 3,"3"] ~id:(module IntCmp)) = 2 ;;size(fromArray([(2, "2"), (2, "1"), (3, "3")], ~id=(module IntCmp))) == 2;val toArray : ('k, 'v, 'id) t -> ('k * 'v) arraylet toArray: t('k, 'v, 'id) => array(('k, 'v));toArray s
toArray (fromArray [2,"2"; 1,"1"; 3,"3"] ~id:(module IntCmp)) = [1,"1";2,"2";3,"3"]toArray(fromArray([(2, "2"), (1, "1"), (3, "3")], ~id=(module IntCmp)))
== [(1, "1"), (2, "2"), (3, "3")];val toList : ('k, 'v, 'id) t -> ('k * 'v) listlet toList: t('k, 'v, 'id) => list(('k, 'v));In increasing order
See toArray
val fromArray : ('k * 'v) array -> id:('k, 'id) id -> ('k, 'v, 'id) tlet fromArray: array(('k, 'v)) => id:id('k, 'id) => t('k, 'v, 'id);fromArray kvs ~id
toArray (fromArray [2,"2"; 1,"1"; 3,"3"] ~id:(module IntCmp)) = [1,"1";2,"2";3,"3"]toArray(fromArray([(2, "2"), (1, "1"), (3, "3")], ~id=(module IntCmp)))
== [(1, "1"), (2, "2"), (3, "3")];val keysToArray : ('k, 'v, 'id) t -> 'k arraylet keysToArray: t('k, 'v, 'id) => array('k);keysToArray s
keysToArray (fromArray [2,"2"; 1,"1"; 3,"3"] ~id:(module IntCmp)) =
[|1;2;3|];;keysToArray(
fromArray([(2, "2"), (1, "1"), (3, "3")], ~id=(module IntCmp)),
)
== [|1, 2, 3|];val valuesToArray : ('k, 'v, 'id) t -> 'v arraylet valuesToArray: t('k, 'v, 'id) => array('v);valuesToArray s
valuesToArray (fromArray [2,"2"; 1,"1"; 3,"3"] ~id:(module IntCmp)) =
[|"1";"2";"3"|];;valuesToArray(
fromArray([(2, "2"), (1, "1"), (3, "3")], ~id=(module IntCmp)),
)
== [|"1", "2", "3"|];val minKey : ('k, _, _) t -> 'k optionlet minKey: t('k, _, _) => option('k);minKey s
returns the minimum key, None if not exist
val minKeyUndefined : ('k, _, _) t -> 'k Js.undefinedlet minKeyUndefined: t('k, _, _) => Js.undefined('k);See minKey
val maxKey : ('k, _, _) t -> 'k optionlet maxKey: t('k, _, _) => option('k);maxKey s
returns the maximum key, None if not exist
val maxKeyUndefined : ('k, _, _) t -> 'k Js.undefinedlet maxKeyUndefined: t('k, _, _) => Js.undefined('k);See maxKey
val minimum : ('k, 'v, _) t -> ('k * 'v) optionlet minimum: t('k, 'v, _) => option(('k, 'v));minimum s
returns the minimum key value pair, None if not exist
val minUndefined : ('k, 'v, _) t -> ('k * 'v) Js.undefinedlet minUndefined: t('k, 'v, _) => Js.undefined(('k, 'v));See minimum
val maximum : ('k, 'v, _) t -> ('k * 'v) optionlet maximum: t('k, 'v, _) => option(('k, 'v));maximum s
returns the maximum key value pair, None if not exist
val maxUndefined : ('k, 'v, _) t -> ('k * 'v) Js.undefinedlet maxUndefined: t('k, 'v, _) => Js.undefined(('k, 'v));See maximum
val get : ('k, 'v, 'id) t -> 'k -> 'v optionlet get: t('k, 'v, 'id) => 'k => option('v);get s k
get (fromArray [2,"2"; 1,"1"; 3,"3"] ~id:(module IntCmp)) 2 =
Some "2";;
get (fromArray [2,"2"; 1,"1"; 3,"3"] ~id:(module IntCmp)) 2 =
None;;get(fromArray([(2, "2"), (1, "1"), (3, "3")], ~id=(module IntCmp)), 2)
== Some("2");
get(fromArray([(2, "2"), (1, "1"), (3, "3")], ~id=(module IntCmp)), 2)
== None;val getUndefined : ('k, 'v, 'id) t -> 'k -> 'v Js.undefinedlet getUndefined: t('k, 'v, 'id) => 'k => Js.undefined('v);See get
returns undefined when not found
val getWithDefault : ('k, 'v, 'id) t -> 'k -> 'v -> 'vlet getWithDefault: t('k, 'v, 'id) => 'k => 'v => 'v;getWithDefault s k default
See get
returns default when k is not found
val getExn : ('k, 'v, 'id) t -> 'k -> 'vlet getExn: t('k, 'v, 'id) => 'k => 'v;getExn s k
See getExn
raise when k not exist
val remove : ('k, 'v, 'id) t -> 'k -> ('k, 'v, 'id) tlet remove: t('k, 'v, 'id) => 'k => t('k, 'v, 'id);remove m x when x is not in m, m is returned reference unchanged.
let s0 = (fromArray [2,"2"; 1,"1"; 3,"3"] ~id:(module IntCmp));;
let s1 = remove s0 1;;
let s2 = remove s1 1;;
s1 == s2 ;;
keysToArray s1 = [|2;3|];;let s0 = fromArray([(2, "2"), (1, "1"), (3, "3")], ~id=(module IntCmp));
let s1 = remove(s0, 1);
let s2 = remove(s1, 1);
s1 === s2;
keysToArray(s1) == [|2, 3|];val removeMany : ('k, 'v, 'id) t -> 'k array -> ('k, 'v, 'id) tlet removeMany: t('k, 'v, 'id) => array('k) => t('k, 'v, 'id);removeMany s xs
Removing each of xs to s, note unlike remove, the reference of return value might be changed even if none in xs exists s
val set : ('k, 'v, 'id) t -> 'k -> 'v -> ('k, 'v, 'id) tlet set: t('k, 'v, 'id) => 'k => 'v => t('k, 'v, 'id);set m x y returns a map containing the same bindings as m, with a new binding of x to y. If x was already bound in m, its previous binding disappears.
let s0 = (fromArray [2,"2"; 1,"1"; 3,"3"] ~id:(module IntCmp));;
let s1 = set s0 2 "3";;
valuesToArray s1 = ["1";"3";"3"];;let s0 = fromArray([(2, "2"), (1, "1"), (3, "3")], ~id=(module IntCmp));
let s1 = set(s0, 2, "3");
valuesToArray(s1) == ["1", "3", "3"];val updateU :
('k, 'v, 'id) t ->
'k ->
('v option -> 'v option) Js.Fn.arity1 ->
('k, 'v, 'id) tlet updateU:
t('k, 'v, 'id) =>
'k =>
Js.Fn.arity1((option('v) => option('v))) =>
t('k, 'v, 'id);val update :
('k, 'v, 'id) t ->
'k ->
('v option -> 'v option) ->
('k, 'v, 'id) tlet update:
t('k, 'v, 'id) =>
'k =>
(option('v) => option('v)) =>
t('k, 'v, 'id);update m x f returns a map containing the same bindings as m, except for the binding of x. Depending on the value of y where y is f (get x m), the binding of x is added, removed or updated. If y is None, the binding is removed if it exists; otherwise, if y is Some z then x is associated to z in the resulting map.
val mergeMany : ('k, 'v, 'id) t -> ('k * 'v) array -> ('k, 'v, 'id) tlet mergeMany: t('k, 'v, 'id) => array(('k, 'v)) => t('k, 'v, 'id);mergeMany s xs
Add each of xs to s, note unlike set, the reference of return value might be changed even if all values in xs exist s
val mergeU :
('k, 'v, 'id) t ->
('k, 'v2, 'id) t ->
('k -> 'v option -> 'v2 option -> 'v3 option) Js.Fn.arity3 ->
('k, 'v3, 'id) tlet mergeU:
t('k, 'v, 'id) =>
t('k, 'v2, 'id) =>
Js.Fn.arity3(('k => option('v) => option('v2) => option('v3))) =>
t('k, 'v3, 'id);val merge :
('k, 'v, 'id) t ->
('k, 'v2, 'id) t ->
('k -> 'v option -> 'v2 option -> 'v3 option) ->
('k, 'v3, 'id) tlet merge:
t('k, 'v, 'id) =>
t('k, 'v2, 'id) =>
('k => option('v) => option('v2) => option('v3)) =>
t('k, 'v3, 'id);merge m1 m2 f computes a map whose keys is a subset of keys of m1 and of m2. The presence of each such binding, and the corresponding value, is determined with the function f.
val keepU :
('k, 'v, 'id) t ->
('k -> 'v -> bool) Js.Fn.arity2 ->
('k, 'v, 'id) tlet keepU:
t('k, 'v, 'id) =>
Js.Fn.arity2(('k => 'v => bool)) =>
t('k, 'v, 'id);val keep : ('k, 'v, 'id) t -> ('k -> 'v -> bool) -> ('k, 'v, 'id) tlet keep: t('k, 'v, 'id) => ('k => 'v => bool) => t('k, 'v, 'id);keep m p returns the map with all the bindings in m that satisfy predicate p.
val partitionU :
('k, 'v, 'id) t ->
('k -> 'v -> bool) Js.Fn.arity2 ->
('k, 'v, 'id) t * ('k, 'v, 'id) tlet partitionU:
t('k, 'v, 'id) =>
Js.Fn.arity2(('k => 'v => bool)) =>
(t('k, 'v, 'id), t('k, 'v, 'id));val partition :
('k, 'v, 'id) t ->
('k -> 'v -> bool) ->
('k, 'v, 'id) t * ('k, 'v, 'id) tlet partition:
t('k, 'v, 'id) =>
('k => 'v => bool) =>
(t('k, 'v, 'id), t('k, 'v, 'id));partition m p returns a pair of maps (m1, m2), where m1 contains all the bindings of s that satisfy the predicate p, and m2 is the map with all the bindings of s that do not satisfy p.
val split :
('k, 'v, 'id) t ->
'k ->
(('k, 'v, 'id) t * ('k, 'v, 'id) t) * 'v optionlet split:
t('k, 'v, 'id) =>
'k =>
((t('k, 'v, 'id), t('k, 'v, 'id)), option('v));split x m returns a tuple (l r), data, where l is the map with all the bindings of m whose 'k is strictly less than x; r is the map with all the bindings of m whose 'k is strictly greater than x; data is None if m contains no binding for x, or Some v if m binds v to x.
val mapU : ('k, 'v, 'id) t -> ('v -> 'v2) Js.Fn.arity1 -> ('k, 'v2, 'id) tlet mapU: t('k, 'v, 'id) => Js.Fn.arity1(('v => 'v2)) => t('k, 'v2, 'id);val map : ('k, 'v, 'id) t -> ('v -> 'v2) -> ('k, 'v2, 'id) tlet map: t('k, 'v, 'id) => ('v => 'v2) => t('k, 'v2, 'id);map m f returns a map with same domain as m, where the associated value a of all bindings of m has been replaced by the result of the application of f to a. The bindings are passed to f in increasing order with respect to the ordering over the type of the keys.
val mapWithKeyU :
('k, 'v, 'id) t ->
('k -> 'v -> 'v2) Js.Fn.arity2 ->
('k, 'v2, 'id) tlet mapWithKeyU:
t('k, 'v, 'id) =>
Js.Fn.arity2(('k => 'v => 'v2)) =>
t('k, 'v2, 'id);val mapWithKey : ('k, 'v, 'id) t -> ('k -> 'v -> 'v2) -> ('k, 'v2, 'id) tlet mapWithKey: t('k, 'v, 'id) => ('k => 'v => 'v2) => t('k, 'v2, 'id);mapWithKey m f
The same as map except that f is supplied with one more argument: the key
val getData : ('k, 'v, 'id) t -> ('k, 'v, 'id) Belt__.Belt_MapDict.tlet getData: t('k, 'v, 'id) => Belt__.Belt_MapDict.t('k, 'v, 'id);getData s0
Advanced usage only
returns the raw data (detached from comparator), but its type is still manifested, so that user can pass identity directly without boxing
val getId : ('k, 'v, 'id) t -> ('k, 'id) idlet getId: t('k, 'v, 'id) => id('k, 'id);getId s0
Advanced usage only
returns the identity of s0
val packIdData :
id:('k, 'id) id ->
data:('k, 'v, 'id) Belt__.Belt_MapDict.t ->
('k, 'v, 'id) tlet packIdData:
id:id('k, 'id) =>
data:Belt__.Belt_MapDict.t('k, 'v, 'id) =>
t('k, 'v, 'id);packIdData ~id ~data
Advanced usage only
returns the packed collection