Belt_List
Utilities for List data type.
This module is compatible with original ocaml stdlib. In general, all functions comes with the original stdlib also applies to this collection, however, this module provides faster and stack safer utilities
let length: t('a) => int;
length xs
let head: t('a) => option('a);
head xs
returns None
if xs
is the empty list, otherwise it returns Some value
where value
is the first element in the list.
head [] = None ;;
head [1;2;3] = Some 1 ;;
tail xs
returns None
if xs
is empty; otherwise it returns Some xs2
where xs2
is everything except the first element of xs
;
tail [] = None;;
tail [1;2;3;4] = Some [2;3;4];;
let get: t('a) => int => option('a);
get xs n
return the nth element in xs
, or None
if n
is larger than the length
get [0;3;32] 2 = Some 32 ;;
get [0;3;32] 3 = None;;
let make: int => 'a => t('a);
make n v
n
with each element filled with value v
n
is negativemake 3 1 = [1;1;1]
let makeByU: int => Js.Fn.arity1((int => 'a)) => t('a);
let makeBy: int => (int => 'a) => t('a);
makeBy n f
n
with element i
initialized with f i
n
is negativemakeBy 5 (fun i -> i) = [0;1;2;3;4];;
makeBy 5 (fun i -> i * i) = [0;1;4;9;16];;
drop xs n
return the list obtained by dropping the first n
elements, or None
if xs
has fewer than n
elements
drop [1;2;3] 2 = Some [3];;
drop [1;2;3] 3 = Some [];;
drop [1;2;3] 4 = None;;
take xs n
return a list with the first n
elements from xs
, or None
if xs
has fewer than n
elements
take [1;2;3] 1 = Some [1];;
take [1;2;3] 2 = Some [1;2];;
take [1;2;3] 4 = None;;
let splitAt: t('a) => int => option((list('a), list('a)));
splitAt xs n
split the list xs
at position n
return None when the length of xs
is less than n
splitAt [0;1;2;3;4] 2 = Some ([0;1], [2;3;4])
concatMany a
return the list obtained by concatenating in order all the lists in array a
concatMany [| [1;2;3] ; []; [3]; [4] |] = [1;2;3;3;4]
reverseConcat xs ys
is equivalent to concat (reverse xs) ys
reverseConcat [1;2] [3;4] = [2;1;3;4]
flatten ls
return the list obtained by concatenating in order all the lists in list ls
flatten [ [1;2;3] ; []; [3]; [4] ] = [1;2;3;3;4]
let mapU: t('a) => Js.Fn.arity1(('a => 'b)) => t('b);
map xs f
return the list obtained by applying f
to each element of xs
map [1;2] (fun x-> x + 1) = [3;4]
let zipByU: t('a) => t('b) => Js.Fn.arity2(('a => 'b => 'c)) => t('c);
zipBy xs ys f
See zip
Equivalent to zip xs ys |> List.map (fun (x,y) -> f x y)
zipBy [1;2;3] [4;5] (fun a b -> 2 * a + b) = [6;9];;
let mapWithIndexU: t('a) => Js.Fn.arity2((int => 'a => 'b)) => t('b);
mapWithIndex xs f
applies f
to each element of xs
. Function f
takes two arguments: the index starting from 0 and the element from xs
.
mapWithIndex [1;2;3] (fun i x -> i + x) =
[0 + 1; 1 + 2; 2 + 3 ]
let fromArray: array('a) => t('a);
fromArray arr
converts the given array to a list
fromArray [|1;2;3|] = [1;2;3]
let toArray: t('a) => array('a);
toArray xs
converts the given list to an array
toArray [1;2;3] = [|1;2;3|]
reverse xs
returns a new list whose elements are those of xs
in reverse order.
reverse [1;2;3] = [3;2;1]
let mapReverseU: t('a) => Js.Fn.arity1(('a => 'b)) => t('b);
mapReverse xs f
Equivalent to reverse (map xs f)
mapReverse [3;4;5] (fun x -> x * x) = [25;16;9];;
let forEachU: t('a) => Js.Fn.arity1(('a => 'b)) => unit;
let forEach: t('a) => ('a => 'b) => unit;
forEach xs f
Call f
on each element of xs
from the beginning to end. f
returns unit
, so no new array is created. Use foreach
when you are primarily concerned with repetitively creating side effects.
forEach ["a";"b";"c"] (fun x -> Js.log("Item: " ^ x));;
(* prints:
Item: a
Item: b
Item: c
*)
let us = ref 0;;
forEach [1;2;3;4] (fun x -> us := !us + x);;
!us = 1 + 2 + 3 + 4;;
let forEachWithIndexU: t('a) => Js.Fn.arity2((int => 'a => 'b)) => unit;
let forEachWithIndex: t('a) => (int => 'a => 'b) => unit;
forEachWithIndex xs f
forEach ["a";"b";"c"] (fun i x -> Js.log("Item " ^ (string_of_int i) ^ " is " ^ x));;
(* prints:
Item 0 is a
Item 1 is b
Item 2 is cc
*)
let total = ref 0 ;;
forEachWithIndex [10;11;12;13] (fun i x -> total := !total + x + i);;
!total = 0 + 10 + 1 + 11 + 2 + 12 + 3 + 13;;
let reduceU: t('a) => 'b => Js.Fn.arity2(('b => 'a => 'b)) => 'b;
let reduce: t('a) => 'b => ('b => 'a => 'b) => 'b;
reduce xs f
Applies f
to each element of xs
from beginning to end. Function f
has two parameters: the item from the list and an “accumulator”, which starts with a value of init
. reduce
returns the final value of the accumulator.
reduce [1;2;3;4] 0 (+) = 10;;
reduce [1;2;3;4] 10 (-) = 0;;
reduce [1;2;3;4] [] add = [4;3;2;1];
let reduceWithIndexU:
t('a) =>
'b =>
Js.Fn.arity3(('b => 'a => int => 'b)) =>
'b;
let reduceWithIndex: t('a) => 'b => ('b => 'a => int => 'b) => 'b;
reduceWithIndex xs f
Applies f
to each element of xs
from beginning to end. Function f
has three parameters: the item from the list and an “accumulator”, which starts with a value of init
and the index of each element. reduceWithIndex
returns the final value of the accumulator.
reduceWithIndex [1;2;3;4] 0 (fun acc x i -> acc + x + i) = 16;;
let reduceReverseU: t('a) => 'b => Js.Fn.arity2(('b => 'a => 'b)) => 'b;
let reduceReverse: t('a) => 'b => ('b => 'a => 'b) => 'b;
reduceReverse xs f
Works like reduce
, except that function f
is applied to each item of xs
from the last back to the first.
reduceReverse [1;2;3;4] 0 (+) = 10;;
reduceReverse [1;2;3;4] 10 (-) = 0;;
reduceReverse [1;2;3;4] [] add = [1;2;3;4];;
let mapReverse2U: t('a) => t('b) => Js.Fn.arity2(('a => 'b => 'c)) => t('c);
mapReverse2 xs ys f
equivalent to reverse (zipBy xs ys f)
mapReverse2 [1;2;3] [1;2] (+) = [4;2]
let forEach2U: t('a) => t('b) => Js.Fn.arity2(('a => 'b => 'c)) => unit;
forEach2 xs ys f
stop with the shorter list
let reduce2U:
t('b) =>
t('c) =>
'a =>
Js.Fn.arity3(('a => 'b => 'c => 'a)) =>
'a;
reduce2 xs ys init f
Applies f
to each element of xs
and ys
from beginning to end. Stops with the shorter list. Function f
has three parameters: an “accumulator” which starts with a value of init
, an item from xs
, and an item from ys
. reduce2
returns the final value of the accumulator.
reduce2 [1;2;3] [4;5] 0 (fun acc x y -> acc + x * x + y) = 0 + (1 * 1 + 4) + (2 * 2 + 5);;
reduce2 [1;2;3] [4;5] [] (fun acc x y -> add acc (x + y) = [2 +5;1 + 4 ];; (*add appends at end *)
let reduceReverse2U:
t('a) =>
t('b) =>
'c =>
Js.Fn.arity3(('c => 'a => 'b => 'c)) =>
'c;
reduceReverse2 xs ys init f
Applies f
to each element of xs
and ys
from end to beginning. Stops with the shorter list. Function f
has three parameters: an “accumulator” which starts with a value of init
, an item from xs
, and an item from ys
. reduce2
returns the final value of the accumulator.
reduceReverse2 [1;2;3] [4;5] 0 (fun acc x y -> acc + x * x + y) = 0 + (1 * 1 + 4) + (2 * 2 + 5);;
reduceReverse2 [1;2;3] [4;5] [] (fun acc x y -> add acc (x + y) = [1 + 4;2 + 5];; (*add appends at end *)
let everyU: t('a) => Js.Fn.arity1(('a => bool)) => bool;
let every: t('a) => ('a => bool) => bool;
every xs p
let someU: t('a) => Js.Fn.arity1(('a => bool)) => bool;
let some: t('a) => ('a => bool) => bool;
some xs p
let every2U: t('a) => t('b) => Js.Fn.arity2(('a => 'b => bool)) => bool;
every2 xs ys p
returns true if predicate p xi yi
is true for all pairs of elements up to the shorter length (i.e. min (length xs) (length ys)
)
every2 [1;2;3] [0;1] (>) = true;;
every2 [] [1] (fun x y -> x > y) = true;;
every2 [2;3] [1] (fun x y -> x > y) = true;;
every2 [0;1] [5;0] (fun x y -> x > y) = false;
let some2U: t('a) => t('b) => Js.Fn.arity2(('a => 'b => bool)) => bool;
some2 xs ys p
returns true if p xi yi
is true for any pair of elements up to the shorter length (i.e. min (length xs) (length ys)
)
some2 [0;2] [1;0;3] (>) = true ;;
some2 [] [1] (fun x y -> x > y) = false;;
some2 [2;3] [1;4] (fun x y -> x > y) = true;;
cmpByLength l1 l2
Compare two lists solely by length. Returns -1 if length l1
is less than length l2
, 0 if length l1
equals length l2
, and 1 if length l1
is greater than length l2
.
cmpByLength [1;2] [3;4;5;6] = -1;;
cmpByLength [1;2;3] [4;5;6] = 0;;
cmpByLength [1;2;3;4] [5;6] = 1;;
let cmpU: t('a) => t('a) => Js.Fn.arity2(('a => 'a => int)) => int;
Compare elements one by one f x y
. f
returns
x
is “less than” y
x
is “equal to” y
x
is “greater than” y
The comparison returns the first non-zero result of f
, or zero if f
returns zero for all x
and y
. If all items have compared equal, but xs
is exhausted first, return -1. (xs
is shorter) If all items have compared equal, but ys
is exhausted first, return 1 (xs
is longer)cmp [3] [3;7] (fun a b -> compare a b) = -1
cmp [5;3] [5] (fun a b -> compare a b) = 1
cmp [|1; 3; 5|] [|1; 4; 2|] (fun a b -> compare a b) = -1;;
cmp [|1; 3; 5|] [|1; 2; 3|] (fun a b -> compare a b) = 1;;
cmp [|1; 3; 5|] [|1; 3; 5|] (fun a b -> compare a b) = 0;;
Attention: The total ordering of List is different from Array, for Array, we compare the length first and, only if the lengths are equal, elements one by one. For lists, we just compare elements one by one
let eqU: t('a) => t('a) => Js.Fn.arity2(('a => 'a => bool)) => bool;
eq xs ys eqElem
check equality of xs
and ys
using eqElem
for equality on elements, where eqElem
is a function that returns true if items x
and y
meet some criterion for equality, false otherwise. eq
false if length of xs
and ys
are not the same.
eq [1;2;3] [1;2] (=) = false ;;
eq [1;2] [1;2] (=) = true;;
eq [1; 2; 3] [-1; -2; -3] (fun a b -> abs a = abs b) = true;;
let hasU: t('a) => 'b => Js.Fn.arity2(('a => 'b => bool)) => bool;
let has: t('a) => 'b => ('a => 'b => bool) => bool;
has xs eqFcn
returns true if the list contains at least one element for which eqFcn x
returns true
has [1;2;3] 2 (=) = true;;
has [1;2;3] 4 (=) = false;;
has [-1;-2;-3] 2 (fun a b -> abs a = abs b) = true;;
let getByU: t('a) => Js.Fn.arity1(('a => bool)) => option('a);
let getBy: t('a) => ('a => bool) => option('a);
getBy xs p
returns Some value
for the first value in xs
that satisifies the predicate function p
; returns None
if no element satisifies the function.
getBy [1;4;3;2] (fun x -> x mod 2 = 0) = Some 4
getBy [15;13;11] (fun x -> x mod 2 = 0) = None
let keepU: t('a) => Js.Fn.arity1(('a => bool)) => t('a);
keep xs p
returns a list of all elements in xs
which satisfy the predicate function p
keep [1;2;3;4] (fun x -> x mod 2 = 0) =
[2;4]
filter xs p
returns a list of all elements in xs
which satisfy the predicate function p
filter [1;2;3;4] (fun x -> x mod 2 = 0) =
[2;4]
let keepWithIndexU: t('a) => Js.Fn.arity2(('a => int => bool)) => t('a);
keepWithIndex xs p
returns a list of all elements in xs
which satisfy the predicate function p
keepWithIndex [1;2;3;4] (fun _x i -> i mod 2 = 0)
=
[1;3]
filterWithIndex xs p
returns a list of all elements in xs
which satisfy the predicate function p
filterWithIndex [1;2;3;4] (fun _x i -> i mod 2 = 0)
=
[1;3]
let keepMapU: t('a) => Js.Fn.arity1(('a => option('b))) => t('b);
keepMap xs f
applies f
to each element of xs
. If f xi
returns Some value
, then value
is kept in the resulting list; if f xi
returns None
, the element is not retained in the result.
keepMap [1;2;3;4] (fun x -> if x mod 2 = 0 then Some (-x ) else None)
=
[-2;-4]
let partitionU: t('a) => Js.Fn.arity1(('a => bool)) => (t('a), t('a));
partition xs p
creates a pair of lists; the first list consists of all elements of xs
that satisfy the predicate function p
; the second list consists of all elements of xs
that do not satisfy p
partition [1;2;3;4] (fun x -> x mod 2 = 0) =
([2;4], [1;3])
unzip xs
takes a list of pairs and creates a pair of lists. The first list contains all the first items of the pairs; the second list contains all the second items.
unzip [(1,2) ; (3,4)] = ([1;3], [2;4]);;
unzip [(1,2) ; (3,4) ; (5,6) ; (7,8)] = ([1;3;5;7], [2;4;6;8]);;
let getAssocU:
t(('a, 'c)) =>
'b =>
Js.Fn.arity2(('a => 'b => bool)) =>
option('c);
let getAssoc: t(('a, 'c)) => 'b => ('a => 'b => bool) => option('c);
getAssoc xs k eq
return the second element of a pair in xs
where the first element equals x
as per the predicate function eq
, or None
if not found
getAssoc [ 1, "a"; 2, "b"; 3, "c"] 2 (=) = Some "b"
getAssoc [9, "morning"; 15, "afternoon"; 22, "night"] 3 (fun a b -> a mod 12 = b mod 12) = Some "afternoon"
let hasAssocU: t(('a, 'c)) => 'b => Js.Fn.arity2(('a => 'b => bool)) => bool;
let hasAssoc: t(('a, 'c)) => 'b => ('a => 'b => bool) => bool;
hasAssoc xs k eq
return true if there is a pair in xs
where the first element equals k
as per the predicate funtion eq
hasAssoc [1, "a"; 2, "b"; 3,"c"] 1 (=) = true;;
hasAssoc [9, "morning"; 15, "afternoon"; 22, "night"] 3 (fun a b -> a mod 12 = b mod 12) = true;;
let removeAssocU:
t(('a, 'c)) =>
'b =>
Js.Fn.arity2(('a => 'b => bool)) =>
t(('a, 'c));
removeAssoc xs k eq
Return a list after removing the first pair whose first value is k
per the equality predicate eq
; if not found, return a new list identical to xs
.
removeAssoc [1,"a"; 2, "b"; 3, "c" ] 1 (=) =
[2, "b"; 3, "c"]
removeAssoc [1,"a"; 2, "b"; 3, "c" ] 99 (=) =
[1, "a"; 2, "b"; 3, "c"]
let setAssocU:
t(('a, 'c)) =>
'a =>
'c =>
Js.Fn.arity2(('a => 'a => bool)) =>
t(('a, 'c));
setAssoc xs k v eq
if k
exists in xs
by satisfying the eq
predicate, return a new list with the key and value replaced by the new k
and v
; otherwise, return a new list with the pair k, v
added to the head of xs
.
setAssoc [1,"a"; 2, "b"; 3, "c"] 2 "x" (=) =
[1,"a"; 2, "x"; 3,"c"] ;;
setAssoc [1,"a"; 3, "c"] 2 "b" (=) =
[2,"b"; 1,"a"; 3, "c"]
setAssoc [9, "morning"; 3, "morning?!"; 22, "night"] 15 "afternoon"
(fun a b -> a mod 12 = b mod 12) = [9, "morning"; 15, "afternoon"; 22, "night"]
Note carefully the last example! Since 15 mod 12
equals 3 mod 12
, both the key and value are replaced in the list.
let sortU: t('a) => Js.Fn.arity2(('a => 'a => int)) => t('a);