Arrays are dynamically-sized sequences of elements, all of the same type.

#Creating Arrays

Use bracket syntax for array literals:

let numbers = [1, 2, 3, 4, 5];
let names = ["Alice", "Bob", "Charlie"];

With an explicit type annotation:

let scores: Array(Int) = [100, 95, 87];

An empty slice can use a type annotation:

var points: Array(Point) = [];
points.add(Point(x=1, y=2));

Use .repeat(n) to create an array by repeating elements:

var zeros = [0].repeat(10);      // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
let dashes = ["-"].repeat(5);    // ["-", "-", "-", "-", "-"]
let pattern = [1, 2].repeat(6);  // [1, 2, 1, 2, 1, 2]

When the source array has multiple elements, they tile to fill the requested count.

#Accessing Elements

Use bracket indexing (zero-based):

let first = numbers[0];   // 1
let third = numbers[2];   // 3

#Length

Use Len() to get the number of elements:

let items = [10, 20, 30];
Println(Len(items));       // 3

#Iterating

Use for-in to loop over elements:

let fruits = ["apple", "banana", "cherry"];
for fruit in fruits {
    Println(fruit);
}

With an index:

for i, fruit in fruits {
    Println("{i}: {fruit}");
}

#Containment

Use .exists() to check if an array contains a value:

let nums = [10, 20, 30];
if nums.exists(20) {
    Println("found 20");
}

#Safe Indexing with .get()

Use .get(index, default) to safely access an element by index. If the index is out of bounds, the default value is returned instead of panicking:

let parts = "a,b,c".split(",");
let first = parts.get(0, "");     // "a"
let fourth = parts.get(3, "");    // "" (out of bounds)
let neg = parts.get(-1, "none");  // "none" (negative index)

// Chainable with other methods
let val = parts.get(2, "").strip();

This is especially useful for parsing lines with optional fields:

let fields = line.split(",");
let name = fields.get(0, "");
let email = fields.get(1, "");
let role = fields.get(2, "member");  // default to "member" if missing

Use .last() to read the final element directly:

let vals = [10, 20, 30];
Println(vals.last());   // 30

let empty: Array(Int) = [];
Println(empty.last());  // 0 (zero value for element type)

#Modifying Arrays

Zenth provides methods to append, prepend, and remove elements from an array. The array must be assigned to a mutable var to use these methods.

#Index Assignment

Assign directly to an index using bracket notation. The array must be a mutable var:

var nums = [10, 20, 30];
nums[1] = 99;            // [10, 99, 30]
nums[0] = nums[0] + 5;   // [15, 99, 30]

Index assignment on an immutable let binding is a compile-time error.

#Adding Elements

  • .add(value) appends an element to the end of the array.
  • .push(value) prepends an element to the beginning of the array.
  • .extend(other) appends all elements from another array of the same type.
var items = [2, 3];
items.add(4);   // [2, 3, 4]
items.push(1);  // [1, 2, 3, 4]

var nums = [1, 2];
nums.extend([3, 4, 5]);  // [1, 2, 3, 4, 5]

#Inserting Elements

  • .insert(index, value) inserts an element at the specified index, shifting later elements right.
var nums = [1, 2, 4, 5];
nums.insert(2, 3);  // [1, 2, 3, 4, 5]

#Removing Elements

  • .pop() removes and returns the last element of the array.
  • .pop(index) removes and returns the element at the specified index.
  • .remove(index) removes the element at the specified index (discards it).
var letters = ["a", "b", "c", "d"];
let last = letters.pop();    // "d", letters is now ["a", "b", "c"]
let first = letters.pop(0);  // "a", letters is now ["b", "c"]

var items = [10, 20, 30];
items.remove(1);  // removes 20, items is now [10, 30]

Use .remove() instead of .pop() when you don’t need the removed value.

#Max and Min

Use .max() and .min() to find the largest and smallest elements of a numeric array:

let nums = [3, 1, 4, 1, 5, 9, 2, 6];
Println(nums.max());       // 9
Println(nums.min());       // 1

let floats = [3.14, 2.71, 1.41];
Println(floats.max());     // 3.14
Println(floats.min());     // 1.41

These methods work on any numeric array (Int, Float) and panic at runtime if called on an empty array.

#Sum

Use .sum() to compute the sum of a numeric array:

let nums = [1, 2, 3, 4, 5];
Println(nums.sum());       // 15

let floats = [1.5, 2.5, 3.0];
Println(floats.sum());     // 7

Returns zero for empty arrays.

#Sorted

Use .sorted() to get a new sorted copy of an array. Works on numeric and string arrays:

let unsorted = [3, 1, 4, 1, 5, 9];
let s = unsorted.sorted();  // [1, 1, 3, 4, 5, 9]
// unsorted is unchanged

let words = ["banana", "apple", "cherry"];
let sw = words.sorted();  // ["apple", "banana", "cherry"]

Pass "desc" to sort in descending order (largest to smallest), or "asc" for ascending (smallest to largest, the default):

let nums = [3, 1, 4, 1, 5];
let asc = nums.sorted("asc");    // [1, 1, 3, 4, 5]
let desc = nums.sorted("desc");  // [5, 4, 3, 1, 1]

let words = ["banana", "apple", "cherry"];
let rev = words.sorted("desc");  // ["cherry", "banana", "apple"]

The original array is not modified. Strings are sorted lexicographically.

#Reduce

Use .reduce() to combine all elements into a single value using a closure that takes an accumulator and element:

let nums = [1, 2, 3, 4, 5];

// Sum all elements
let total = nums.reduce(fn(a, b) a + b);
Println(total);  // 15

// Product with initial value
let product = nums.reduce(fn(a, b) a * b, 1);
Println(product);  // 120

// Find max using reduce
let biggest = nums.reduce(fn(a, b) if a > b { a } else { b });
Println(biggest);  // 5

Without an initial value, the first element is used as the starting accumulator and reduction begins from the second element. Calling reduce() on an empty array without an initial value panics at runtime.

With an initial value, reduction starts from that value and processes all elements:

let nums = [1, 2, 3];
let sum_from_100 = nums.reduce(fn(a, b) a + b, 100);
Println(sum_from_100);  // 106

Works on any array type — numeric, string, etc. The closure must take two parameters of the element type and return the same type.

#Join

Use .join(separator) to concatenate all elements of a string array into a single string, with the given separator between each element:

let words = ["hello", "world"];
Println(words.join(" "));      // "hello world"

let csv = ["a", "b", "c"];
Println(csv.join(","));        // "a,b,c"

// Empty separator concatenates directly
let letters = ["x", "y", "z"];
Println(letters.join(""));     // "xyz"

// Multi-character separator
let parts = ["2026", "03", "15"];
Println(parts.join("-"));      // "2026-03-15"

Only works on Array(Str). Calling .join() on a non-string array is a compile-time error.

#Enumerate

Use .enumerate() to pair each element with its index, returning an Array(Tuple(Int, T)):

let fruits = ["apple", "banana", "cherry"];
let indexed = fruits.enumerate();
for pair in indexed {
    Println("{pair.0}: {pair.1}");
}
// 0: apple
// 1: banana
// 2: cherry

This is especially useful with .filter() and .map() when you need access to the original index during functional-style chaining. Closures with multiple parameters automatically destructure the tuple:

let items = ["foo", "bar", "baz", "qux"];

// Filter with index access
let evens = items.enumerate().filter(fn(i, v) i % 2 == 0);
for pair in evens {
    Println("{pair.0}: {pair.1}");
}
// 0: foo
// 2: baz

// Map with index access
let labeled = items.enumerate().map(fn(i, s) "{i}: {s}");
// ["0: foo", "1: bar", "2: baz", "3: qux"]

// Full pipeline: enumerate + filter + map
let tasks = ["done", "active", "done", "active"];
let active_ids = tasks.enumerate()
    .filter(fn(i, t) t == "active")
    .map(fn(i, t) i + 1);
// [2, 4]  (1-based line numbers of active tasks)

When a closure passed to .filter() or .map() has the same number of parameters as the tuple elements, each parameter receives the corresponding tuple element (index, value). You can also use a single parameter and access .0 / .1 on the tuple.

#Transforming Arrays

Use .map() to transform each element and .filter() to select elements:

let numbers = [1, 2, 3, 4, 5];

// Double each element
let doubled = numbers.map(fn(x) x * 2);
// [2, 4, 6, 8, 10]

// Keep only even numbers
let evens = numbers.filter(fn(x) x % 2 == 0);
// [2, 4]

// Chaining
let result = numbers.filter(fn(x) x > 2).map(fn(x) x * 10);
// [30, 40, 50]

Closures with a block body use explicit return:

let processed = numbers.map(fn(x: Int) -> Int {
    let y = x + 10;
    return y;
});

#Destructuring

Use array destructuring to bind array elements directly to variables. The syntax mirrors slice literals: let [a, b, c] = expr:

let nums = [10, 20, 30];
let [a, b, c] = nums;
Println(a);  // 10
Println(b);  // 20
Println(c);  // 30

Works with let, var, and const:

var [x, y] = [1, 2];
x = 99;      // ok: x is mutable

Use _ to discard positions you don’t need:

let [first, _, third] = [1, 2, 3];
Println(first);  // 1
Println(third);  // 3

Especially useful with method chains:

let line = "12x4x8";
let [l, w, h] = line.split("x").to_int().sorted();
Println(l);  // 4
Println(w);  // 8
Println(h);  // 12

The number of binding names must not exceed the array length at runtime; a runtime panic occurs if the array is too short.

#Example

fn sum(numbers: Array(Int)) -> Int {
    var total = 0;
    for n in numbers {
        total += n;
    }
    return total;
}

fn main() {
    let data = [1, 2, 3, 4, 5];
    Println("Sum: {sum(data)}");
}