Belt_Array
Utililites for Array
functions.
Note about index syntax
Code like arr[0]
does not compile to JavaScript arr[0]
. Reason transforms the []
index syntax into a function: Array.get(arr, 0)
. By default, this uses the default standard library's Array.get
function, which may raise an exception if the index isn't found. If you open Belt
, it will use the Belt.Array.get
function which returns options instead of raising exceptions. See this for more information.
t
type t<'a> = array<'a>
length
return the size of the array
RES// Returns 1
Belt.Array.length(["test"])
let length: t<'a> => int
size
See length
let size: t<'a> => int
get
If i <= 0 <= length(arr)
returns Some(value)
where value
is the item at index i
.
If i
is out of range returns None
.
Belt.Array.get(["a", "b", "c"], 0) == Some("a") Belt.Array.get(["a", "b", "c"], 3) == None Belt.Array.get(["a", "b", "c"], -1) == None
let get: (t<'a>, int) => option<'a>
getExn
Raise an exception if i
is out of range.
Otherwise return the value at index i
in arr
.
let getExn: (t<'a>, int) => 'a
getUnsafe
getUnsafe(arr, i)
Unsafe
no bounds checking; this would cause type error if i
does not stay within range
let getUnsafe: (t<'a>, int) => 'a
getUndefined
getUndefined(arr, i)
It does the samething in the runtime as getUnsafe
;
it is type safe since the return type still track whether it is
in range or not
let getUndefined: (t<'a>, int) => Js.undefined<'a>
set
set(arr, n, x)
modifies arr
in place; it replaces the nth element of arr
with x
.
Returning false
means not updated due to out of range.
let set: (t<'a>, int, 'a) => bool
setExn
setExn(arr, i, x)
raise an exception if i
is out of range.
let setExn: (t<'a>, int, 'a) => unit
setUnsafe
let setUnsafe: (t<'a>, int, 'a) => unit
shuffleInPlace
shuffleInPlace(arr)
randomly re-orders the items in arr
let shuffleInPlace: t<'a> => unit
shuffle
Returns a fresh array with items in original array randomly shuffled.
let shuffle: t<'a> => t<'a>
reverseInPlace
reverseInPlace(arr)
reverses items in arr
in place.
RESlet arr = [10, 11, 12, 13, 14]
let () = Belt.Array.reverseInPlace(arr)
arr == [14, 13, 12, 11, 10]
let reverseInPlace: t<'a> => unit
reverse
reverse(arr)
returns a fresh array with items in arr in reverse order.
RESBelt.Array.reverse([10, 11, 12, 13, 14]) == [14, 13, 12, 11, 10]
let reverse: t<'a> => t<'a>
makeUninitialized
makeUninitialized(n)
creates an array of length n
filled with the undefined value. You must specify the type of data that will eventually fill the array.
RESlet arr: array<Js.undefined<string>> = Belt.Array.makeUninitialized(5)
Belt.Array.getExn(arr, 0) == Js.undefined
let makeUninitialized: int => array<Js.undefined<'a>>
makeUninitializedUnsafe
Unsafe
RESlet arr = Belt.Array.makeUninitializedUnsafe(5)
Js.log(Belt.Array.getExn(arr, 0)) // undefined
Belt.Array.setExn(arr, 0, "example")
Js.log(Belt.Array.getExn(arr, 0) == "example")
let makeUninitializedUnsafe: int => t<'a>
make
make(n, e)
return an array of size n
filled with value e
.
Returns an empty array when n
is negative.
let make: (int, 'a) => t<'a>
range
range(start, finish)
create an inclusive array.
RESBelt.Array.range(0, 3) == [0, 1, 2, 3]
Belt.Array.range(3, 0) == []
Belt.Array.range(3, 3) == [3]
let range: (int, int) => array<int>
rangeBy
rangeBy(start, finish, ~step)
Returns empty array when step is 0 or negative. It also return an empty array when start > finish
.
RESBelt.Array.rangeBy(0, 10, ~step=3) == [0, 3, 6, 9]
Belt.Array.rangeBy(0, 12, ~step=3) == [0, 3, 6, 9, 12]
Belt.Array.rangeBy(33, 0, ~step=1) == []
Belt.Array.rangeBy(33, 0, ~step=-1) == []
Belt.Array.rangeBy(3, 12, ~step=-1) == []
Belt.Array.rangeBy(3, 3, ~step=0) == []
Belt.Array.rangeBy(3, 3, ~step=1) == [3]
let rangeBy: (int, int, ~step: int) => array<int>
makeByU
let makeByU: (int, (. int) => 'a) => t<'a>
makeBy
makeBy(n, f)
Return an empty array when n is negative return an array of size n populated by f(i)
start from 0
to n - 1
.
RESBelt.Array.makeBy(5, (i) => i) == [0, 1, 2, 3, 4]
Belt.Array.makeBy(5, (i) => i * i) == [0, 1, 4, 9, 16]
let makeBy: (int, int => 'a) => t<'a>
makeByAndShuffleU
let makeByAndShuffleU: (int, (. int) => 'a) => t<'a>
makeByAndShuffle
Equivalent to shuffle(makeBy(n, f))
let makeByAndShuffle: (int, int => 'a) => t<'a>
zip
zip(a, b)
Create an array of pairs from corresponding elements of a and b. Stop with the shorter array.
RESBelt.Array.zip([1, 2], [3, 4, 5]) == [(1, 3), (2, 4)]
let zip: (t<'a>, array<'b>) => array<('a, 'b)>
zipByU
let zipByU: (t<'a>, array<'b>, (. 'a, 'b) => 'c) => array<'c>
zipBy
zipBy(xs, ys, f)
Create an array by applying f
to corresponding elements of xs
and ys
. Stops with shorter array.
Equivalent to map(zip(xs, ys), ((a, b)) => f(a, b))
RESBelt.Array.zipBy([1, 2, 3], [4, 5], (a, b) => 2 * a + b) == [6, 9]
let zipBy: (t<'a>, array<'b>, ('a, 'b) => 'c) => array<'c>
unzip
unzip(a)
takes an array of pairs and creates a pair of arrays. The first array contains all the first items of the pairs; the second array contains all the second items.
RESBelt.Array.unzip([(1, 2), (3, 4)]) == ([1, 3], [2, 4])
Belt.Array.unzip([(1, 2), (3, 4), (5, 6), (7, 8)]) == ([1, 3, 5, 7], [2, 4, 6, 8])
let unzip: array<('a, 'b)> => (t<'a>, array<'b>)
concat
concat(xs, ys)
Returns a fresh array containing the concatenation of the arrays v1
and v2
;so even if v1
or v2
is empty; it can not be shared
RESBelt.Array.concat([1, 2, 3], [4, 5]) == [1, 2, 3, 4, 5]
Belt.Array.concat([], ["a", "b", "c"]) == ["a", "b", "c"]
let concat: (t<'a>, t<'a>) => t<'a>
concatMany
concatMany(xss)
Returns a fresh array as the concatenation of xss
(an array of arrays)
RESBelt.Array.concatMany([[1, 2, 3], [4, 5, 6], [7, 8]]) == [1, 2, 3, 4, 5, 6, 7, 8]
let concatMany: array<t<'a>> => t<'a>
slice
slice(xs, offset, len)
creates a new array with the len elements of xs
starting at offset
for offset
can be negative;and is evaluated as
length(xs) - offset(slice, xs) - 1(1)
means get the last element as a
singleton array slice(xs, ~-len, len)
will return a copy of the array if the
array does not have enough data; slice
extracts through the end of sequence.
if len
is negative; returns the empty array.
RESBelt.Array.slice([10, 11, 12, 13, 14, 15, 16], ~offset=2, ~len=3) == [12, 13, 14]
Belt.Array.slice([10, 11, 12, 13, 14, 15, 16], ~offset=-4, ~len=3) == [13, 14, 15]
Belt.Array.slice([10, 11, 12, 13, 14, 15, 16], ~offset=4, ~len=9) == [14, 15, 16]
let slice: (t<'a>, ~offset: int, ~len: int) => t<'a>
sliceToEnd
sliceToEnd(xs, offset)
creates a new array with the elements of xs
starting at offset
offset
can be negative; and is evaluated as length(xs) - offset(sliceToEnd, xs) - 1
means get the last element as a singleton array
sliceToEnd(xs, 0)
will return a copy of the array
RESBelt.Array.sliceToEnd([10, 11, 12, 13, 14, 15, 16], 2) == [12, 13, 14, 15, 16]
Belt.Array.sliceToEnd([10, 11, 12, 13, 14, 15, 16], -4) == [13, 14, 15, 16]
let sliceToEnd: (t<'a>, int) => t<'a>
copy
copy(a)
Returns a copy of a; that is; a fresh array containing the same elements as a.
let copy: t<'a> => t<'a>
fill
fill(arr, ~offset, ~len, x)
Modifies arr
in place, storing x
in elements number offset
to offset + len - 1
.
offset
can be negative; and is evaluated as length(arr - offset)
fill(arr, ~offset=-1, ~len=1)
means fill the last element, if the array does not have enough data; fill
will ignore it
RESlet arr = Belt.Array.makeBy(5, (i) => i)
Belt.Array.fill(arr, ~offset=2, ~len=2, 9)
arr == [0, 1, 9, 9, 4]
Belt.Array.fill(arr, ~offset=7, ~len=2, 8)
arr == [0, 1, 9, 9, 4]
```res sig
let fill: (t<'a>, ~offset: int, ~len: int, 'a) => unit
blit
blit(~src=v1, ~srcOffset=o1, ~dst=v2, ~dstOffset=o2, ~len)
copies len
elements from array v1
;starting at element number o1
;to array v2
, starting at element number o2
.
It works correctly even if v1
and v2
are the same array;and the source and destination chunks overlap.
offset
can be negative; -1
means len - 1
; if len + offset
is still negative;it will be set as 0
For each of the examples;presume that v1 == [10, 11, 12, 13, 14, 15, 16, 17]
and v2 == [20, 21, 22, 23, 24, 25, 26, 27]
. The result shown is the content of the destination array.
RESlet v1 = [10, 11, 12, 13, 14, 15, 16, 17]
let v2 = [20, 21, 22, 23, 24, 25, 26, 27]
Belt.Array.blit(~src=v1, ~srcOffset=4, ~dst=v2, ~dstOffset=2, ~len=3)
v2 == [20, 21, 14, 15, 16, 25, 26, 27]
Belt.Array.blit(~src=v1, ~srcOffset=4, ~dst=v1, ~dstOffset=2, ~len=3)
v1 == [10, 11, 14, 15, 16, 15, 16, 17]
let blit: (~src: t<'a>, ~srcOffset: int, ~dst: t<'a>, ~dstOffset: int, ~len: int) => unit
blitUnsafe
Unsafe blit without bounds checking.
let blitUnsafe: (~src: t<'a>, ~srcOffset: int, ~dst: t<'a>, ~dstOffset: int, ~len: int) => unit
forEachU
let forEachU: (t<'a>, (. 'a) => unit) => unit
forEach
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.
RESBelt.Array.forEach(["a", "b", "c"], x => Js.log("Item: " ++ x))
/*
prints:
Item: a
Item: b
Item: c
*/
let total = ref(0)
Belt.Array.forEach([1, 2, 3, 4], x => total := total.contents + x)
total.contents == 1 + 2 + 3 + 4
let forEach: (t<'a>, 'a => unit) => unit
mapU
let mapU: (t<'a>, (. 'a) => 'b) => array<'b>
map
map(xs, f)
Returns a new array by calling f
for each element of xs
from the beginning to end.
RESBelt.Array.map([1, 2], (x) => x + 1) == [3, 4]
let map: (t<'a>, 'a => 'b) => array<'b>
flatMapU
let flatMapU: (t<'a>, (. 'a) => array<'b>) => array<'b>
flatMap
flatMap(xs, f)
Returns a new array by calling f
for each element of xs
from
the beginning to end, concatenating the results.
RESflatMap([1, 2], x => [x + 10, x + 20]) == [11, 21, 12, 22]
let flatMap: (t<'a>, 'a => array<'b>) => array<'b>
getByU
let getByU: (t<'a>, (. 'a) => bool) => option<'a>
getBy
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.
RESBelt.Array.getBy([1, 4, 3, 2], (x) => mod(x, 2) == 0) == Some(4)
Belt.Array.getBy([15, 13, 11], (x) => mod(x, 2) == 0) == None
let getBy: (t<'a>, 'a => bool) => option<'a>
getIndexByU
let getIndexByU: (t<'a>, (. 'a) => bool) => option<int>
getIndexBy
getIndexBy(xs, p)
returns Some(index)
for the first value in xs
that satisifies the predicate function p
;
returns None
if no element satisifies the function.
RESBelt.Array.getIndexBy([1, 4, 3, 2], (x) => mod(x, 2) == 0) == Some(1)
Belt.Array.getIndexBy([15, 13, 11], (x) => mod(x, 2) == 0) == None
let getIndexBy: (t<'a>, 'a => bool) => option<int>
keepU
let keepU: (t<'a>, (. 'a) => bool) => t<'a>
keep
keep(xs, p)
returns a new array that keep all elements satisfy p
.
let keep: (t<'a>, 'a => bool) => t<'a>
keepWithIndexU
let keepWithIndexU: (t<'a>, (. 'a, int) => bool) => t<'a>
keepWithIndex
keepWithIndex(xs, p)
Returns a new array that keep all elements satisfy p
.
RESBelt.Array.keepWithIndex([1, 2, 3], (_x, i) => i == 1) == [2]
let keepWithIndex: (t<'a>, ('a, int) => bool) => t<'a>
keepMapU
let keepMapU: (t<'a>, (. 'a) => option<'b>) => array<'b>
keepMap
keepMap(xs, p)
Returns a new array that keep all elements that return a non-None applied p
.
RESBelt.Array.keepMap([1, 2, 3], x =>
if mod(x, 2) == 0 {
Some(x)
} else {
None
}
)
== [2]
let keepMap: (t<'a>, 'a => option<'b>) => array<'b>
forEachWithIndexU
let forEachWithIndexU: (t<'a>, (. int, 'a) => unit) => unit
forEachWithIndex
forEachWithIndex(xs, f)
The same as Belt.Array.forEach
;
except that f
is supplied two arguments: the index starting from 0 and the element from xs
.
RESBelt.Array.forEachWithIndex(["a", "b", "c"], (i, x) => Js.log("Item " ++ Belt.Int.toString(i) ++ " is " ++ x))
/*
prints:
Item 0 is a
Item 1 is b
Item 2 is cc
*/
let total = ref(0)
Belt.Array.forEachWithIndex([10, 11, 12, 13], (i, x) => total := total.contents + x + i)
total.contents == 0 + 10 + 1 + 11 + 2 + 12 + 3 + 13
let forEachWithIndex: (t<'a>, (int, 'a) => unit) => unit
mapWithIndexU
let mapWithIndexU: (t<'a>, (. int, 'a) => 'b) => array<'b>
mapWithIndex
mapWithIndex(xs, f)
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
.
RESBelt.Array.mapWithIndex([1, 2, 3], (i, x) => i + x) == [0 + 1, 1 + 2, 2 + 3]
let mapWithIndex: (t<'a>, (int, 'a) => 'b) => array<'b>
partitionU
let partitionU: (t<'a>, (. 'a) => bool) => (t<'a>, t<'a>)
partition
partition(f, a)
split array into tuple of two arrays based on predicate f
; first of tuple where predicate cause true, second where predicate cause false
RESBelt.Array.partition([1, 2, 3, 4, 5], (x) => mod(x, 2) == 0) == ([2, 4], [1, 3, 5])
Belt.Array.partition([1, 2, 3, 4, 5], (x) => mod(x, 2) != 0) == ([1, 3, 5], [2, 4])
let partition: (t<'a>, 'a => bool) => (t<'a>, t<'a>)
reduceU
let reduceU: (array<'b>, 'a, (. 'a, 'b) => 'a) => 'a
reduce
reduce(xs, init, 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.
RESBelt.Array.reduce([2, 3, 4], 1, (a, b) => a + b) == 10
Belt.Array.reduce(["a", "b", "c", "d"], "", (a, b) => a ++ b) == "abcd"
let reduce: (array<'b>, 'a, ('a, 'b) => 'a) => 'a
reduceReverseU
let reduceReverseU: (array<'b>, 'a, (. 'a, 'b) => 'a) => 'a
reduceReverse
reduceReverse(xs, init, f)
Works like Belt_Array.reduce
; except that function f
is applied to each item of xs
from the last back to the first.
RESBelt.Array.reduceReverse(["a", "b", "c", "d"], "", (a, b) => a ++ b) == "dcba"
let reduceReverse: (array<'b>, 'a, ('a, 'b) => 'a) => 'a
reduceReverse2U
let reduceReverse2U: (t<'a>, array<'b>, 'c, (. 'c, 'a, 'b) => 'c) => 'c
reduceReverse2
reduceReverse2(xs, ys, init, f)
Reduces two arrays xs and ys;taking items starting at min(length(xs), length(ys))
down to and including zero.
RESBelt.Array.reduceReverse2([1, 2, 3], [1, 2], 0, (acc, x, y) => acc + x + y) == 6
let reduceReverse2: (t<'a>, array<'b>, 'c, ('c, 'a, 'b) => 'c) => 'c
reduceWithIndexU
let reduceWithIndexU: (t<'a>, 'b, (. 'b, 'a, int) => 'b) => 'b
reduceWithIndex
Applies f
to each element of xs
from beginning to end. Function f
has three parameters: the item from the array and an “accumulator”, which starts with a value of init
and the index of each element. reduceWithIndex
returns the final value of the accumulator.
RESBelt.Array.reduceWithIndex([1, 2, 3, 4], 0, (acc, x, i) => acc + x + i) == 16
let reduceWithIndex: (t<'a>, 'b, ('b, 'a, int) => 'b) => 'b
joinWithU
let joinWithU: (t<'a>, string, (. 'a) => string) => string
joinWith
joinWith(xs, sep, toString)
Concatenates all the elements of xs
converted to string with toString
, each separated by sep
, the string
given as the second argument, into a single string.
If the array has only one element, then that element will be returned
without using the separator.
If the array is empty, the empty string will be returned.
RESjoinWith([0, 1], ", ", string_of_int) == "0, 1"
joinWith([], " ", string_of_int) == ""
joinWith([1], " ", string_of_int) == "1"
let joinWith: (t<'a>, string, 'a => string) => string
someU
let someU: (t<'a>, (. 'a) => bool) => bool
some
some(xs, p)
Returns true if at least one of the elements in xs
satifies p
; where p
is a predicate: a function taking an element and returning a bool
.
RESBelt.Array.some([2, 3, 4], (x) => mod(x, 2) == 1) == true
Belt.Array.some([(-1), (-3), (-5)], (x) => x > 0) == false
let some: (t<'a>, 'a => bool) => bool
everyU
let everyU: (t<'a>, (. 'a) => bool) => bool
every
every(xs, p)
Returns true
if all elements satisfy p
; where p
is a predicate: a function taking an element and returning a bool
.
RESBelt.Array.every([1, 3, 5], (x) => mod(x, 2) == 1) == true
Belt.Array.every([1, (-3), 5], (x) => x > 0) == false
let every: (t<'a>, 'a => bool) => bool
every2U
let every2U: (t<'a>, array<'b>, (. 'a, 'b) => bool) => bool
every2
every2(xs, ys, p)
returns true if p(xi, yi)
is true for all pairs of elements up to the shorter length (i.e. min(length(xs), length(ys))
)
RESBelt.Array.every2([1, 2, 3], [0, 1], (a, b) => a > b) == true
Belt.Array.every2([], [1], (x, y) => x > y) == true
Belt.Array.every2([2, 3], [1], (x, y) => x > y) == true
Belt.Array.every2([0, 1], [5, 0], (x, y) => x > y) == false
let every2: (t<'a>, array<'b>, ('a, 'b) => bool) => bool
some2U
let some2U: (t<'a>, array<'b>, (. 'a, 'b) => bool) => bool
some2
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))
)
RESBelt.Array.some2([0, 2], [1, 0, 3], (a, b) => a > b) == true
Belt.Array.some2([], [1], (x, y) => x > y) == false
Belt.Array.some2([2, 3], [1, 4], (x, y) => x > y) == true
let some2: (t<'a>, array<'b>, ('a, 'b) => bool) => bool
cmpU
let cmpU: (t<'a>, t<'a>, (. 'a, 'a) => int) => int
cmp
cmp(xs, ys, f)
Compared by length if length(xs) != length(ys)
; returning -1 if length(xs) < length(ys)
or 1 if length(xs) > length(ys)
Otherwise compare one by one f(x, y)
. f
returns
a negative number if x
is “less than” y
zero if x
is “equal to” y
a positive number if 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
.
RESBelt.Array.cmp([1, 3, 5], [1, 4, 2], (a, b) => compare(a, b)) == -1
Belt.Array.cmp([1, 3, 5], [1, 2, 3], (a, b) => compare(a, b)) == 1
Belt.Array.cmp([1, 3, 5], [1, 3, 5], (a, b) => compare(a, b)) == 0
let cmp: (t<'a>, t<'a>, ('a, 'a) => int) => int
eqU
let eqU: (t<'a>, t<'a>, (. 'a, 'a) => bool) => bool
eq
eq(xs, ys)
return false if length is not the same
otherwise compare items one by one using f(xi, yi)
; and return true if all results are truefalse otherwise
RESBelt.Array.eq([1, 2, 3], [(-1), (-2), (-3)], (a, b) => abs(a) == abs(b)) == true
let eq: (t<'a>, t<'a>, ('a, 'a) => bool) => bool
truncateToLengthUnsafe
Unsafe truncateToLengthUnsafe(xs, n)
sets length of array xs
to n
.
If n
is greater than the length of xs
; the extra elements are set to Js.Null_undefined.null
.
If n
is less than zero; raises a RangeError
.
RESlet arr = ["ant", "bee", "cat", "dog", "elk"]
Belt.Array.truncateToLengthUnsafe(arr, 3)
arr == ["ant", "bee", "cat"]
let truncateToLengthUnsafe: (t<'a>, int) => unit
initU
let initU: (int, (. int) => 'a) => t<'a>
init
let init: (int, int => 'a) => t<'a>
push
arr->push(item)
pushes an element item
into an array arr
.
let push: (t<'a>, 'a) => unit