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.
length
let length: array<'a> => int
return the size of the array
RES// Returns 1
Belt.Array.length(["test"])
size
let size: array<'a> => int
See Belt_Array.length
get
let get: (array<'a>, int) => option<'a>
If i <= 0 <= length(arr)
returns Some(value)
where value
is the item at index i
.
If i
is out of range returns None
getExn
let getExn: (array<'a>, int) => 'a
Raise an exception if i
is out of range.
Otherwise return the value at index i
in arr
.
getUnsafe
let getUnsafe: (array<'a>, int) => 'a
Unsafe
no bounds checking; this would cause type error if i
does not stay within range
getUndefined
let getUndefined: (array<'a>, int) => Js.undefined<'a>
It does the samething in the runtime as Belt_Array.getUnsafe
it is type safe since the return type still track whether it is in range or not
set
let set: (array<'a>, int, 'a) => bool
set(arr, n, x)
modifies arr
in place; it replaces the nth element of arr
with x
.
Returns false means not updated due to out of range.
setExn
let setExn: (array<'a>, int, 'a) => unit
setExn(arr, i, x)
raise an exception if i
is out of range.
setUnsafe
let setUnsafe: (array<'a>, int, 'a) => unit
shuffleInPlace
let shuffleInPlace: array<'a> => unit
shuffleInPlace(arr)
randomly re-orders the items in arr
shuffle
let shuffle: array<'a> => array<'a>
Returns a fresh array with items in original array randomly shuffled.
reverseInPlace
let reverseInPlace: array<'a> => unit
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]
reverse
let reverse: array<'a> => array<'a>
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]
makeUninitialized
let makeUninitialized: int => array<Js.undefined<'a>>
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
makeUninitializedUnsafe
let makeUninitializedUnsafe: int => array<'a>
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")
make
let make: (int, 'a) => array<'a>
make(n, e)
return an array of size n
filled with value e
.
Returns an empty array when n
is negative.
range
let range: (int, int) => array<int>
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]
rangeBy
let rangeBy: (int, int, ~step: int) => array<int>
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]
makeByU
let makeByU: (int, (. int) => 'a) => array<'a>
makeBy
let makeBy: (int, int => 'a) => array<'a>
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]
makeByAndShuffleU
let makeByAndShuffleU: (int, (. int) => 'a) => array<'a>
makeByAndShuffle
let makeByAndShuffle: (int, int => 'a) => array<'a>
makeByAndShuffle(n, f)
Equivalent to shuffle(makeBy(n, f))
zip
let zip: (array<'a>, array<'b>) => array<('a, 'b)>
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)]
zipByU
let zipByU: (array<'a>, array<'b>, (. 'a, 'b) => 'c) => array<'c>
zipBy
let zipBy: (array<'a>, array<'b>, ('a, 'b) => 'c) => array<'c>
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]
unzip
let unzip: array<('a, 'b)> => (array<'a>, array<'b>)
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])
concat
let concat: (array<'a>, array<'a>) => array<'a>
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"]
concatMany
let concatMany: array<array<'a>> => array<'a>
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]
slice
let slice: (array<'a>, ~offset: int, ~len: int) => array<'a>
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]
sliceToEnd
let sliceToEnd: (array<'a>, int) => array<'a>
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]
copy
let copy: array<'a> => array<'a>
copy(a)
Returns a copy of a; that is; a fresh array containing the same elements as a.
fill
let fill: (array<'a>, ~offset: int, ~len: int, 'a) => unit
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]
blit
let blit:
(
~src: array<'a>,
~srcOffset: int,
~dst: array<'a>,
~dstOffset: int,
~len: int
) =>
unit
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]
blitUnsafe
let blitUnsafe: (~src: array<'a>, ~srcOffset: int, ~dst: array<'a>, ~dstOffset: int, ~len: int) => unit
Unsafe blit without bounds checking.
forEachU
let forEachU: (array<'a>, (. 'a) => unit) => unit
forEach
let forEach: (array<'a>, 'a => unit) => 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.
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
mapU
let mapU: (array<'a>, (. 'a) => 'b) => array<'b>
map
let map: (array<'a>, 'a => 'b) => array<'b>
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]
getByU
let getByU: (array<'a>, (. 'a) => bool) => option<'a>
getBy
let getBy: (array<'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.
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
getIndexByU
let getIndexByU: (array<'a>, (. 'a) => bool) => option<int>
getIndexBy
let getIndexBy: (array<'a>, 'a => bool) => option<int>
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
keepU
let keepU: (array<'a>, (. 'a) => bool) => array<'a>
keep
let keep: (array<'a>, 'a => bool) => array<'a>
keep(xs, p)
Returns a new array that keep all elements satisfy p
.
RESBelt.Array.keep([1, 2, 3], (x) => mod(x, 2) == 0) == [2]
keepWithIndexU
let keepWithIndexU: (array<'a>, (. 'a, int) => bool) => array<'a>
keepWithIndex
let keepWithIndex: (array<'a>, ('a, int) => bool) => array<'a>
keepWithIndex(xs, p)
Returns a new array that keep all elements satisfy p
.
RESBelt.Array.keepWithIndex([1, 2, 3], (_x, i) => i == 1) == [2]
keepMapU
let keepMapU: (array<'a>, (. 'a) => option<'b>) => array<'b>
keepMap
let keepMap: (array<'a>, 'a => option<'b>) => array<'b>
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]
forEachWithIndexU
let forEachWithIndexU: (array<'a>, (. int, 'a) => unit) => unit
forEachWithIndex
let forEachWithIndex: (array<'a>, (int, 'a) => unit) => unit
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
mapWithIndexU
let mapWithIndexU: (array<'a>, (. int, 'a) => 'b) => array<'b>
mapWithIndex
let mapWithIndex: (array<'a>, (int, 'a) => 'b) => array<'b>
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]
partitionU
let partitionU: (array<'a>, (. 'a) => bool) => (array<'a>, array<'a>)
partition
let partition: (array<'a>, 'a => bool) => (array<'a>, array<'a>)
partition(xs, p)
split array into tuple of two arrays based on predicate p
; 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])
reduceU
let reduceU: (array<'b>, 'a, (. 'a, 'b) => 'a) => 'a
reduce
let reduce: (array<'b>, 'a, ('a, 'b) => 'a) => 'a
reduce(arr, init, f)
Applies f
to each element of arr
.
Function f
has two parameters: an "accumulator" which starts with a value of init
and the next value
from the array.
It returns the final value of the accumulator.
RESBelt.Array.reduce([2, 3, 4], 1, (acc, value) => acc + value) == 10
Belt.Array.reduce(["a", "b", "c", "d"], "", (a, b) => a ++ b) == "abcd"
reduceReverseU
let reduceReverseU: (array<'b>, 'a, (. 'a, 'b) => 'a) => 'a
reduceReverse
let reduceReverse: (array<'b>, 'a, ('a, 'b) => 'a) => 'a
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"
reduceReverse2U
let reduceReverse2U: (array<'a>, array<'b>, 'c, (. 'c, 'a, 'b) => 'c) => 'c
reduceReverse2
let reduceReverse2: (array<'a>, array<'b>, 'c, ('c, 'a, 'b) => 'c) => 'c
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
reduceWithIndexU
let reduceWithIndexU: (array<'a>, 'b, (. 'b, 'a, int) => 'b) => 'b
reduceWithIndex
let reduceWithIndex: (array<'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 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
someU
let someU: (array<'a>, (. 'a) => bool) => bool
some
let some: (array<'a>, 'a => bool) => bool
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
everyU
let everyU: (array<'a>, (. 'a) => bool) => bool
every
let every: (array<'a>, 'a => bool) => bool
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
every2U
let every2U: (array<'a>, array<'b>, (. 'a, 'b) => bool) => bool
every2
let every2: (array<'a>, array<'b>, ('a, 'b) => bool) => bool
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
some2U
let some2U: (array<'a>, array<'b>, (. 'a, 'b) => bool) => bool
some2
let some2: (array<'a>, array<'b>, ('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))
)
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
cmpU
let cmpU: (array<'a>, array<'a>, (. 'a, 'a) => int) => int
cmp
let cmp: (array<'a>, array<'a>, ('a, 'a) => int) => int
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
eqU
let eqU: (array<'a>, array<'a>, (. 'a, 'a) => bool) => bool
eq
let eq: (array<'a>, array<'a>, ('a, 'a) => bool) => bool
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
truncateToLengthUnsafe
let truncateToLengthUnsafe: (array<'a>, int) => unit
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"]