Array/Vector Library
Stof's standard array/vector library ("Array").
In Stof, arrays and vectors are the same thing. We support both nomenclatures because it is common for "array" to be used in data formats, however, an array in most programming contexts is a fixed-capacity compound type that cannot grow in size. In Stof, arrays are implemented as vectors, and the "vec" type makes more sense. This separation also helps distinguish the arrays declared in a document from the "runtime" vectors used to manipulate data.
Common Value Functions
Array.toString(array: vec): str
#[test]
fn test() {
pln([1, 2, 3].toString()); // [1, 2, 3]
pln(Array.toString([4, 5, 6])); // [4, 5, 6]
}
Array.or(array: vec, ...): unknown
Returns the first non-empty (null or void) argument, just like the Standard Library "or" function.
#[test]
fn test() {
let val = [1, 2, 3];
let default = [4, 5];
let x = val.or(default, []);
assertEq(x, [1, 2, 3]);
val = null;
let y = val.or(default, 42, "hello", []);
assertEq(y, [4, 5]);
}
Vector Functions
Array.append(array: vec, other: vec): void
Appends another vector into this array, leaving the other empty. If not boxed, "other" will be cloned when this function is called, and the original vector maintains its values.
#[test]
fn append() {
let a = [1, 2, 3, 4, 5];
let b = [6, 7, 8, 9];
a.append(b);
assertEq(a, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
assertEq(b, [6, 7, 8, 9]);
}
#[test]
fn append_boxed() {
let a = [1, 2, 3, 4, 5];
let b = box([6, 7, 8, 9]);
a.append(b);
assertEq(a, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
assertEq(b, []);
}
Array.push(array: vec, ...): void
Pushes all arguments to the end of the array in order, as they are given.
#[test(["hi"])]
fn push(): vec {
let array = [];
array.push("hi");
return array;
}
Array.pop(array: vec, index?: int | unknown): unknown | null
Pop a value from this array. If an index is not provided, the last element of the array will be removed and returned (null if the array is empty).
If the index is a number, it will be treated as the position within the array to remove and return. An error will be thrown if this index is greater than or equal to the length of the array (indices start at zero).
If the index is a value other than a number, the first value in the array that equals the index value will be removed and returned. If no value in the array equals the index, null is returned.
#[test(["hi"])]
fn pop(): vec {
let array = ["hi", "there"];
assertEq(array.pop(), "there");
return array;
}
#[test([1, 2, 4, 5, 6])]
fn pop_at(): vec {
let array = [1, 2, 3, 4, 5, 6];
assertEq(array.pop(2), 3); // if given a number param, it is treated as an index
return array;
}
#[test(["a", "c", "d", "e"])]
fn pop_val(): vec {
let array: vec = ["a", "b", "c", "d", "e"];
assertEq(array.pop("b"), "b");
return array;
}
Array.reverse(array: vec): void
Reverses the array in place.
#[test]
fn reverse() {
let array = [1, 2, 3, 4];
array.reverse();
assertEq(array, [4, 3, 2, 1]);
}
Array.reversed(array: vec): vec
Clones this array in the reverse order and returns it, leaving the original array unmodified.
#[test]
fn reversed() {
let array = [1, 2, 3, 4];
let reversed = array.reversed();
assertEq(array, [1, 2, 3, 4]);
assertEq(reversed, [4, 3, 2, 1]);
}
Array.len(array: vec): int
The length of this array.
#[test]
fn len() {
let array = [1, 2, 3, 4, 5, 6, 7, 8];
assertEq(array.len(), 8);
}
Array.empty(array: vec): bool
Is this array empty?
#[test]
fn empty() {
let array = [];
assert(array.empty());
array.push(1);
assertNot(array.empty());
}
Array.any(array: vec): bool
Does this array have any values (not empty)?
#[test]
fn any() {
let array = [];
assertNot(array.any());
array.push(1);
assert(array.any());
}
Array.at(array: vec, index: int): unknown
Get a value in this array at a specific index. Will throw an error if the index is out of bounds.
#[test]
fn at() {
let array = [1, 2, 3, 4];
assertEq(array.at(2), 3);
assertEq(array[3], 4);
}
#[test]
fn nested_at() {
let array = [[1, 2, 3], [4, 5, 6]];
assertEq(array[0][1], 2);
assertEq(array.at(1).at(2), 6);
}
#[test]
fn loops() {
let vals = [];
for (i in 0..10) vals.push(i); // 0..10 is a range array constructor
assertEq(vals, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
}
Array.first(array: vec): unknown | null
Returns the first value in the array (cloned) or null if the array is empty.
#[test(1)]
fn first(): int {
let array = [1, 2, 3];
return array.first();
}
Array.last(array: vec): unknown | null
Returns the last value in the array (cloned) or null if the array is empty.
#[test(3)]
fn last(): int {
let array = [1, 2, 3];
return array.last();
}
Array.join(array: vec, separator: str): str
Joins the values inside this array into a singular string, separated by a "separator" value. This array is unmodified.
#[test("hello, world")]
fn join(): str {
return ["hello", "world"].join(", ");
}
Array.contains(array: vec, value: unknown): bool
Does this array contain a value (equality comparison)?
#[test]
fn contains() {
let array = ["hello", "world"];
assert(array.contains("hello"));
assertNot(array.contains("dne"));
}
Array.find(array: vec, other: unknown): int
Returns the index of the first value in this array to equal "other". If not found, returns -1.
#[test]
fn find() {
let array = ["hello", "world", 5];
assertEq(array.find(5), 2);
assertEq(array.find("world"), 1);
assertEq(array.find("dne"), -1);
assertEq(array.find(2), -1);
}
Array.remove(array: vec, other: unknown): unknown | null
Removes the first value in the array to equal "other" and returns it. Returns null if not found.
#[test]
fn remove_first_occurence() {
let array = ["hello", "world", 5, 4, "world"];
assertEq(array.remove("dne"), null);
assertEq(array.remove(5), 5);
assertEq(array.remove("world"), "world");
assertEq(array, ['hello', 4, 'world']);
}
Array.removeLast(array: vec, other: unknown): unknown | null
Removes the last value in the array to equal "other" and returns it. Returns null if not found.
#[test]
fn remove_last_occurence() {
let array = ["hello", "world", 4, "world"];
assertEq(array.removeLast("world"), "world");
assertEq(array, ["hello", "world", 4]);
}
Array.removeAll(array: vec, other: unknown): vec
Removes all values in the array that equal "other", returning a vector of all values removed.
#[test]
fn remove_all() {
let array = [1, 1, 1, 1, 2, 1, 1, 1, 1];
assertEq(array.removeAll(1).len(), 8);
assertEq(array, [2]);
assert(array.removeAll(1).empty());
}
Array.insert(array: vec, index: int, ...values: unknown): void
Inserts values into this array at a specific index, shifting existing elements to the right. Must provide at least one value to insert.
Will throw an error if the index is out of bounds or if you do not provide at least one value to insert.
#[test]
fn insert() {
let array = [1, 2, 3, 4, 5, 6];
array.insert(2, "hello");
assertEq(array, [1, 2, 'hello', 3, 4, 5, 6]);
}
Array.set(array: vec, index: int, ...values: unknown): void
Inserts values into this array at a specific index, replacing the existing element at that index. Must provide at least one value to insert.
Will throw an error if the index is out of bounds or if you do not provide at least one value to insert.
#[test]
fn set() {
let array = [1, 2, 3, 4, 5, 6];
array.set(2, "hello");
assertEq(array, [1, 2, "hello", 4, 5, 6]);
array.set(4, 42);
assertEq(array, [1, 2, "hello", 4, 42, 6]);
}
Array.iter(array: vec, func: fn): void
Iterates over this array, calling "func" for each value. If "func" returns a non-null value, that value is then set in place of the existing element. The function passed in must take a singular value as a parameter, in the type you know you are iterating over (or "unknown" to accept all).
#[test]
fn iter() {
let array = 0..15;
array.iter((val: int): int => {
if (val % 2 == 0) {
return val + 1;
}
return null; // don't set anything
});
assertEq(array, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15]);
}
Array.retain(array: vec, func: fn): void
For each value in this array, call "func" (passing the value in as the only argument) - if "func" returns true, keep the value, otherwise, remove the value from the array.
#[test]
fn retain_evens() {
let array = 0..100;
array.retain((v: int): bool => v % 2 == 0);
assertEq(array, 0..100|2);
}
Array.sort(array: vec, func?: fn): void
Sort this array, optionally providing a function to sort with.
If a function is not provided, Stof will use the "less-than" and "greater-than" built-in functions to compare values.
If providing a function, the function should take two value arguments and return -1 for less than, 1 for greater than, or 0 for equal.
#[test([0, 1, 2, 2, 4, 5, 5, 7, 8])]
fn sort(): vec {
let array = [5, 2, 4, 5, 7, 8, 0, 2, 1];
array.sort();
return array;
}
#[test([2, 3, 5, 6, 6])]
fn sort_by(): vec {
let array = [new {k:6}, new {k:3}, new {k:5}, new {k:2}, new {k:6}];
array.sort((a: obj, b: obj): int => {
if (a.k < b.k) return -1;
if (a.k > b.k) return 1;
return 0;
});
let res = [];
for (object in array) {
res.push(object.k);
}
return res;
}
Last updated
Was this helpful?