List

len : List(_item) -> U64

Returns the length of the list, which is equal to the number of elements it contains.

One List can store up to I64.highest elements on 64-bit targets and I32.highest on 32-bit targets like wasm. This means the #U64 this function returns can always be safely converted to #I64 or #I32, depending on the target.

is_empty : List(_item) -> Bool

Check if the list is empty.

[1, 2, 3].is_empty()

[].is_empty()
iter : List(item) -> Iter(item)

Iterate over the list from first to last.

from_iter : Iter(item) -> List(item)

Build a list from a pure Iter, pre-sizing the allocation from the iterator's len_if_known when it is known up front. This is the from_iter that Iter.collect dispatches to.

concat : List(item), List(item) -> List(item)

Put two lists together.

[1.I64, 2, 3].concat([4, 5])

[0.I64, 1, 2].concat([3, 4])
reserve : List(item), U64 -> List(item)

Ensure this list has room for at least spare additional elements.

sort_with : List(item), (item, item -> [LT, EQ, GT]) -> List(item)

Sort a list using a custom comparison function. The comparator receives two elements and returns LT, EQ, or GT to indicate their relative order.

expect [3, 1, 2].sort_with(|a, b| if a < b LT else if a > b GT else EQ) == [1, 2, 3]

# Sort in descending order by swapping the LT and GT
expect [3, 1, 2].sort_with(|a, b| if a > b LT else if a < b GT else EQ) == [3, 2, 1]
is_eq : List(item), List(item) -> Bool where { item.is_eq : item, item -> Bool }

Returns True if the two lists have the same length and their elements are pairwise equal.

to_hash : List(item), Hasher -> Hasher where { item.to_hash : item, Hasher -> Hasher }

Feed a list into a Hasher.

append : List(a), a -> List(a)

Add a single element to the end of a list.

[1.I64, 2, 3].append(4)

[0.I64, 1, 2].append(3)
prepend : List(a), a -> List(a)

Add a single element to the beginning of a list.

expect [2, 3, 4].prepend(1) == [1, 2, 3, 4]

expect [].prepend(0) == [0]
first : List(item) -> Try(item, [ListWasEmpty, ..])

Returns the first element in the list, or ListWasEmpty if it was empty.

expect [1, 2, 3].first() == Ok(1)
expect [].first() == Err(ListWasEmpty)
get : List(item), U64 -> Try(item, [OutOfBounds, ..])

Returns an element from a list at the given index.

Returns Err OutOfBounds if the given index exceeds the List's length

expect [100, 200, 300].get(1) == Ok(200)
expect [100, 200, 300].get(5) == Err(OutOfBounds)
subscript : List(item), U64 -> Try(item, [OutOfBounds, ..])

Alias for List.get, enabling the future list[index] subscript operator. Returns an element from a list at the given index.

Returns Err OutOfBounds if the given index exceeds the List's length

expect ["bird", "lizard"].subscript(0) == Ok("bird")
expect ["bird", "lizard"].subscript(5) == Err(OutOfBounds)
set : List(a), U64, a -> Try(List(a), [OutOfBounds, ..])

Replaces the element at the given index with a new value.

expect [10, 20, 30].set(1, 99) == Ok([10, 99, 30])

expect [10, 20, 30].set(5, 99) == Err(OutOfBounds)
replace : List(a), U64, a -> Try({ list : List(a), prev : a }, [OutOfBounds, ..])

Replaces the element at the given index, returning both the updated list and the value that was replaced.

expect [10, 20, 30].replace(1, 99) == Ok({ list: [10, 99, 30], prev: 20 })
expect [10, 20, 30].replace(5, 99) == Err(OutOfBounds)
update : List(a), U64, (a -> a) -> Try(List(a), [OutOfBounds, ..])

Updates the element at the given index by applying a function to it.

expect [10, 20, 30].update(1, |x| x + 5) == Ok([10, 25, 30])

expect [10, 20, 30].update(5, |x| x + 5) == Err(OutOfBounds)
swap : List(a), U64, U64 -> Try(List(a), [OutOfBounds, ..])

Exchanges the elements at the two given indices.

expect [10, 20, 30, 40].swap(0, 3) == Ok([40, 20, 30, 10])

expect [10, 20, 30].swap(0, 5) == Err(OutOfBounds)
rev : List(item) -> List(item)

Returns the reversed list.

expect [1, 2, 3].rev() == [3, 2, 1]
expect [].rev() == []
map : List(a), (a -> b) -> List(b)

Convert each element in the list to something new, by calling a conversion function on each of them. Then return a new list of the converted values.

expect [1, 2, 3].map(|num| num + 1) == [2, 3, 4]

expect ["", "a", "bc"].map(Str.is_empty) == [Bool.True, Bool.False, Bool.False]
map_with_index : List(a), (a, U64 -> b) -> List(b)

This works like List.map, except it also passes the index of the element to the conversion function.

expect List.map_with_index([10, 20, 30], (|num, index| num + index)) == [10, 21, 32]
map2 : List(a), List(b), (a, b -> c) -> List(c)

Apply a binary function to pairs of elements from two lists, returning a list of results. The result's length is the length of the shorter input list.

expect [1, 2, 3].map2([10, 20, 30], |a, b| a + b) == [11, 22, 33]
expect [1, 2, 3, 4, 5].map2([10, 20], |a, b| a + b) == [11, 22]
keep_if : List(a), (a -> Bool) -> List(a)

Run the given function on each element of a list, and return all the elements for which the function returned Bool.True.

[1.I64, 2, 3, 4].keep_if(|num| num > 2)

## Performance Details

List.keep_if always returns a list that takes up exactly the same amount of memory as the original, even if its length decreases. This is because it can't know in advance exactly how much space it will need, and if it guesses a length that's too low, it would have to re-allocate.

(If you want to do an operation like this which reduces the memory footprint of the resulting list, you can do two passes over the list with List.fold - one to calculate the precise new size, and another to populate the new list.)

If given a unique list, List.keep_if will mutate it in place to assemble the appropriate list. If that happens, this function will not allocate any new memory on the heap. If all elements in the list end up being kept, Roc will return the original list unaltered.

drop_if : List(a), (a -> Bool) -> List(a)

Run the given function on each element of a list, and return all the elements for which the function returned Bool.False.

[1.I64, 2, 3, 4].drop_if(|num| num > 2)

## Performance Details

List.drop_if has the same performance characteristics as List.keep_if. See its documentation for details on those characteristics!

count_if : List(a), (a -> Bool) -> U64

Run the given function on each element of a list, and return the number of elements for which the function returned Bool.True.

expect [1, -2, -3].count_if(I64.is_negative) == 2
expect [1, 2, 3].count_if(|num| num > 1) == 2
fold : List(item), state, (state, item -> state) -> state

Build a value using each element in the list.

Starting with a given state value, this folds through each element in the list from first to last, running a given step function on that element which updates the state. It returns the final state at the end.

[2, 4, 8].fold(0, U64.plus)

This returns 14 because: * state starts at 0 * Each step runs state.plus(elem), and the return value becomes the new state.

Here is a table of how state changes as List.fold folds over the elements [2, 4, 8] using U64.plus as its step function to determine the next state.

state | elem | U64.plus(state, elem) :---: | :---: | :----------------: 0 | | 0 | 2 | 2 2 | 4 | 6 6 | 8 | 14

The following returns -6:

[1, 2, 3].fold(0, I64.minus)

Note that in other languages, fold is sometimes called reduce, fold_left, or foldl.

fold_with_index : List(item), state, (state, item, U64 -> state) -> state

Like List.fold, but at each step the function also receives the index of the current element.

fold_until : List(item), state, (state, item -> [Continue(state), Break(state)]) -> state

Same as List.fold, except you can stop folding early.

## Performance Details

Compared to List.fold, this can potentially visit fewer elements (which can improve performance) at the cost of making each step take longer. However, the added cost to each step is extremely small, and can easily be outweighed if it results in skipping even a small number of elements.

As such, it is typically better for performance to use this over List.fold if returning Break earlier than the last element is expected to be common.

fold_rev : List(item), state, (item, state -> state) -> state

Like List.fold, but walks the list from last to first. The step function receives the element first and the current state second.

expect [1, 2, 3].fold_rev(0, I64.minus) == 2

Here is a table of how state changes as List.fold_rev folds over the elements [1, 2, 3] using I64.minus as its step function.

state | elem | I64.minus(elem, state) :---: | :---: | :-------------------: 0 | | 0 | 3 | 3 3 | 2 | -1 -1 | 1 | 2

Note that in other languages, fold_rev is sometimes called reduce_right, fold_right, or foldr.

starts_with : List(a), List(a) -> Bool where { a.is_eq : a, a -> Bool }

Returns Bool.True if the first list starts with the second list.

If the second list is empty, this always returns Bool.True; every list is considered to "start with" an empty list.

If the first list is empty, this only returns Bool.True if the second list is empty.

ends_with : List(a), List(a) -> Bool where { a.is_eq : a, a -> Bool }

Returns Bool.True if the first list ends with the second list.

If the second list is empty, this always returns Bool.True; every list is considered to "end with" an empty list.

If the first list is empty, this only returns Bool.True if the second list is empty.

any : List(a), (a -> Bool) -> Bool

Run the given predicate on each element of the list, returning Bool.True if any of the elements satisfy it.

expect [1, 2, 3].any(|n| n % 2 == 0)

expect ![1, 2, 3].any(|n| n < 0)
contains : List(a), a -> Bool where { a.is_eq : a, a -> Bool }

Returns Bool.True if the list contains an element equal to the given value.

expect [1, 2, 3].contains(2)

expect ![1, 2, 3].contains(4)
all : List(a), (a -> Bool) -> Bool

Run the given predicate on each element of the list, returning Bool.True if all of the elements satisfy it.

expect [2, 4, 6].all(|n| n % 2 == 0)

expect ![1, 2, 3].all(|n| n % 2 == 0)
last : List(item) -> Try(item, [ListWasEmpty, ..])

Returns the last element in the list, or ListWasEmpty if it was empty.

expect [1, 2, 3].last() == Ok(3.0)
expect [].last() == Err(ListWasEmpty)
single : item -> List(item)

Create a list with a single element in it.

expect List.single(42) == [42.0]
drop_at : List(a), U64 -> List(a)

Remove the element at the given index. If the index is out of bounds, the list is returned unchanged.

expect [10, 20, 30, 40].drop_at(1) == [10, 30, 40]

expect [10, 20, 30].drop_at(5) == [10, 20, 30]
sublist : List(a), { start : U64, len : U64 } -> List(a)

Return a sublist of the list starting at start and containing up to len elements. Out-of-bounds ranges are clamped, producing a shorter or empty list.

expect [1, 2, 3, 4, 5].sublist({ start: 1, len: 3 }) == [2, 3, 4]

expect [1, 2, 3].sublist({ start: 1, len: 10 }) == [2, 3]

expect [1, 2, 3].sublist({ start: 10, len: 2 }) == []
take_first : List(a), U64 -> List(a)

Return the first n elements of the list. If the list has fewer than n elements, the entire list is returned.

expect [1, 2, 3, 4, 5].take_first(3) == [1, 2, 3]

expect [1, 2].take_first(10) == [1, 2]
take_last : List(a), U64 -> List(a)

Returns the given number of elements from the end of the list.

expect [1, 2, 3, 4, 5, 6, 7, 8].take_last(4) == [5, 6, 7, 8]

If there are fewer elements in the list than the requested number, the entire list is returned.

expect [1, 2].take_last(5) == [1, 2]

To *remove* elements from the end of the list, use List.take_first.

To remove elements from both the beginning and end of the list, use List.sublist.

drop_first : List(a), U64 -> List(a)

Drops n elements from the beginning of the list. If n is larger than the list length, an empty list is returned.

expect [1, 2, 3, 4, 5].drop_first(2) == [3, 4, 5]

expect [1, 2, 3].drop_first(10) == []
drop_last : List(a), U64 -> List(a)

Drops n elements from the end of the list. If n is larger than the list length, an empty list is returned.

expect [1, 2, 3, 4, 5].drop_last(2) == [1, 2, 3]

expect [1, 2, 3].drop_last(10) == []
find_first : List(a), (a -> Bool) -> Try(a, [NotFound])

Find the first element in a list that satisfies a given predicate, returning it wrapped in Ok if found, or Err(NotFound) if no such element exists.

expect [1, 2, 3, 4].find_first(|x| x % 2 == 0) == Ok(2)
find_last : List(a), (a -> Bool) -> Try(a, [NotFound])

Find the last element in a list that satisfies a given predicate, returning it wrapped in Ok if found, or Err(NotFound) if no such element exists.

expect [1, 2, 3, 4].find_last(|x| x % 2 == 0) == Ok(4)
find_first_index : List(a), (a -> Bool) -> Try(U64, [NotFound])

Find the index of the first element in a list that satisfies a given predicate, returning it wrapped in Ok if found, or Err(NotFound) if no such element exists.

expect [1, 2, 3, 4].find_first_index(|x| x > 1) == Ok(1)
find_last_index : List(a), (a -> Bool) -> Try(U64, [NotFound])

Find the index of the last element in a list that satisfies a given predicate, returning it wrapped in Ok if found, or Err(NotFound) if no such element exists.

expect [1, 2, 3, 4].find_last_index(|x| x < 4) == Ok(2)
split_at : List(a), U64 -> { before : List(a), others : List(a) }
expect [0, 1, 2, 3, 4].split_at(2) == { before: [0, 1], others: [2, 3, 4] }
split_on : List(a), a -> List(List(a)) where { a.is_eq : a, a -> Bool }

Split a list into sublists using a specified delimiter element.

Consecutive delimiters and delimiters at the start or end of the list produce empty sublists at the corresponding positions.

expect [1, 2, 1, 2, 3].split_on(1) == [[], [2], [2, 3]]
expect [1, 1, 2].split_on(1) == [[], [], [2]]
split_if : List(a), (a -> Bool) -> List(List(a))

Split a list into sublists using a predicate function to identify delimiters.

Consecutive delimiters and delimiters at the start or end of the list produce empty sublists at the corresponding positions.

expect [0, 1, 2, 3, 4].split_if(|x| x % 2 == 0) == [[], [1], [3], []]
split_on_list : List(a), List(a) -> List(List(a)) where { a.is_eq : a, a -> Bool }

Split a list into sublists using a specified delimiter list.

expect [1, 2, 3, 4, 5].split_on_list([2, 3]) == [[1], [4, 5]]
split_first : List(a), a -> Try({ before : List(a), after : List(a) }, [NotFound]) where { a.is_eq : a, a -> Bool }

Split a list into two parts at the first occurrence of a specified delimiter element, returning the part before the delimiter and the part after it. If the delimiter is not found, return Err(NotFound).

expect [0, 1, 2, 1, 2].split_first(2) == Ok({ before: [0, 1], after: [1, 2] })
split_last : List(a), a -> Try({ before : List(a), after : List(a) }, [NotFound]) where { a.is_eq : a, a -> Bool }

Split a list into two parts at the last occurrence of a specified delimiter element, returning the part before the delimiter and the part after it. If the delimiter is not found, return Err(NotFound).

expect [0, 1, 2, 1, 2].split_last(1) == Ok({ before: [0, 1, 2], after: [2] })
repeat : a, U64 -> List(a)

Build a list by repeating the given value n times.

expect List.repeat(0, 3) == [0, 0, 0]

expect List.repeat("hi", 0) == []
sum : List(item) -> item where { item.plus : item, item -> item, item.default : -> item }

Sum the elements of a list. Works for any type that implements plus and default methods, such as the numeric types.

expect List.sum([1.I64, 2, 3, 4]) == 10

expect List.sum([]) == 0.I64
min : List(a) -> Try(a, [ListWasEmpty]) where { a.min : a, a -> a }

Find the minimum element in a list, or Err(ListWasEmpty) if the list is empty. Works for any type that implements min.

max : List(a) -> Try(a, [ListWasEmpty]) where { a.max : a, a -> a }

Find the maximum element in a list, or Err(ListWasEmpty) if the list is empty. Works for any type that implements max.

encoder_for : encoding -> List(item), state -> Try(state, err) where { item.encoder_for : encoding -> item, state -> Try(state, err), encoding.encode_list : state, U64, (state, (state, (state -> Try(state, err)) -> Try(state, err)) -> Try(state, err)) -> Try(state, err) }

Build an encoder for a list using a format that provides a list encoding method.

decode : src, fmt -> (Try(List(item), err), src) where { fmt.decode_list : fmt, src, (src, fmt -> (Try(item, err), src)) -> (Try(List(item), err), src), item.decode : src, fmt -> (Try(item, err), src) }

Decode a list using a format that provides decode_list