Skip to main content
Version: v1.0.0-beta.0

Arrays

An array is one way of grouping together values into one compound type. Array types can be inferred or explicitly specified via the syntax [<Type>; <Size>]:

fn main(x : Field, y : Field) {
let my_arr = [x, y];
let your_arr: [Field; 2] = [x, y];
}

Here, both my_arr and your_arr are instantiated as an array containing two Field elements.

Array elements can be accessed using indexing:

fn main() {
let a = [1, 2, 3, 4, 5];

let first = a[0];
let second = a[1];
}

All elements in an array must be of the same type (i.e. homogeneous). That is, an array cannot group a Field value and a u8 value together for example.

You can write mutable arrays, like:

fn main() {
let mut arr = [1, 2, 3, 4, 5];
assert(arr[0] == 1);

arr[0] = 42;
assert(arr[0] == 42);
}

You can instantiate a new array of a fixed size with the same value repeated for each element. The following example instantiates an array of length 32 where each element is of type Field and has the value 0.

let array: [Field; 32] = [0; 32];

Like in Rust, arrays in Noir are a fixed size. However, if you wish to convert an array to a slice, you can just call as_slice on your array:

let array: [Field; 32] = [0; 32];
let sl = array.as_slice()

You can define multidimensional arrays:

let array : [[Field; 2]; 2];
let element = array[0][0];

However, multidimensional slices are not supported. For example, the following code will error at compile time:

let slice : [[Field]] = &[];

Types

You can create arrays of primitive types or structs. There is not yet support for nested arrays (arrays of arrays) or arrays of structs that contain arrays.

Methods

For convenience, the STD provides some ready-to-use, common methods for arrays. Each of these functions are located within the generic impl impl<T, N> [T; N] {. So anywhere self appears, it refers to the variable self: [T; N].

len

Returns the length of an array

fn len(self) -> Field

example

fn main() {
let array = [42, 42];
assert(array.len() == 2);
}

sort

Returns a new sorted array. The original array remains untouched. Notice that this function will only work for arrays of fields or integers, not for any arbitrary type. This is because the sorting logic it uses internally is optimized specifically for these values. If you need a sort function to sort any type, you should use the function sort_via described below.

fn sort(self) -> [T; N]

example

fn main() {
let arr = [42, 32];
let sorted = arr.sort();
assert(sorted == [32, 42]);
}

sort_via

Sorts the array with a custom comparison function. The ordering function must return true if the first argument should be sorted to be before the second argument or is equal to the second argument.

Using this method with an operator like < that does not return true for equal values will result in an assertion failure for arrays with equal elements.

fn sort_via(self, ordering: fn(T, T) -> bool) -> [T; N]

example

fn main() {
let arr = [42, 32]
let sorted_ascending = arr.sort_via(|a, b| a <= b);
assert(sorted_ascending == [32, 42]); // verifies

let sorted_descending = arr.sort_via(|a, b| a >= b);
assert(sorted_descending == [32, 42]); // does not verify
}

map

Applies a function to each element of the array, returning a new array containing the mapped elements.

fn map<U>(self, f: fn(T) -> U) -> [U; N]

example

let a = [1, 2, 3];
let b = a.map(|a| a * 2); // b is now [2, 4, 6]

fold

Applies a function to each element of the array, returning the final accumulated value. The first parameter is the initial value.

fn fold<U>(self, mut accumulator: U, f: fn(U, T) -> U) -> U

This is a left fold, so the given function will be applied to the accumulator and first element of the array, then the second, and so on. For a given call the expected result would be equivalent to:

let a1 = [1];
let a2 = [1, 2];
let a3 = [1, 2, 3];

let f = |a, b| a - b;
a1.fold(10, f) //=> f(10, 1)
a2.fold(10, f) //=> f(f(10, 1), 2)
a3.fold(10, f) //=> f(f(f(10, 1), 2), 3)

example:


fn main() {
let arr = [2, 2, 2, 2, 2];
let folded = arr.fold(0, |a, b| a + b);
assert(folded == 10);
}

reduce

Same as fold, but uses the first element as the starting element.

Requires self to be non-empty.

fn reduce(self, f: fn(T, T) -> T) -> T

example:

fn main() {
let arr = [2, 2, 2, 2, 2];
let reduced = arr.reduce(|a, b| a + b);
assert(reduced == 10);
}

all

Returns true if all the elements satisfy the given predicate

fn all(self, predicate: fn(T) -> bool) -> bool

example:

fn main() {
let arr = [2, 2, 2, 2, 2];
let all = arr.all(|a| a == 2);
assert(all);
}

any

Returns true if any of the elements satisfy the given predicate

fn any(self, predicate: fn(T) -> bool) -> bool

example:

fn main() {
let arr = [2, 2, 2, 2, 5];
let any = arr.any(|a| a == 5);
assert(any);
}

as_str_unchecked

Converts a byte array of type [u8; N] to a string. Note that this performs no UTF-8 validation - the given array is interpreted as-is as a string.

impl<let N: u32> [u8; N] {
pub fn as_str_unchecked(self) -> str<N>
}

example:

fn main() {
let hi = [104, 105].as_str_unchecked();
assert_eq(hi, "hi");
}