Arrays & slices
Store a sequence, sort it, and take part of it.
On this page
Array[T] is a growable list of values of type T. Slices (&[T]) are views of part of an array, and fixed arrays ([T x N]) hold a set number of items inline.
Create and grow an array#
fn main() {
let scores = Array[int]{ 12, 8 }
scores.append(20)
scores.prepend(5)
scores.insert(1, 7) !!
println(scores.join(", ")) // 5, 7, 12, 8, 20
println(scores.length) // 5
let zeros = Array[int]{ 0 x 4 } // four zeros
let names: Array[String] = .{ "Ada", "Sam" }
let empty = Array[String]{}
println("%{zeros.length} %{names.length} %{empty.length}") // 4 2 0
}
Read and change items#
fn main() {
let items = Array[String]{ "a", "b", "c" }
println(items[0]) // a
println(items.get(5) !? "none") // none
items[1] = "B"
println(items.first() !? "") // a
println(items.last() !? "") // c
println(items.contains("B")) // true
println(items.index_of("c") !? 0) // 2
}
items[i] panics when i is out of range; get(i) throws a LookupError instead, so it can fall back with !?. first, last and index_of also throw when there is nothing to return.
Remove items#
| Method | Effect |
|---|---|
remove(index) |
Remove one item, shift the rest down |
swap_remove(index) |
Remove one item, move the last into its place (faster, changes order) |
remove_value(value) |
Remove the first equal item |
remove_where(fn) |
Remove every item the function accepts |
pop_last(), pop_first() |
Remove and return an end; throws when empty |
remove_duplicates() |
Keep the first of each value |
clear() |
Remove everything |
fn main() {
let values = Array[int]{ 1, 2, 3, 4, 5, 2 }
values.remove(0)
values.remove_where(fn(v) { return v > 4 })
values.remove_duplicates()
let last = values.pop_last() !? 0
println("%{values.join(",")} last=%last") // 2,3 last=4
}
Removing by index inside each over the same array skips the next item; use remove_where instead.
Loop over an array#
fn main() {
let tasks = Array[String]{ "Build", "Test" }
each tasks as task, index : println("%index: %task")
let pairs = Array[(String, int)]{ ("a", 1), ("b", 2) }
each pairs as name, count : print("%name=%count ") // a=1 b=2
println("")
}
An array of tuples can split each item into names; see Control flow for all each forms.
Search and transform#
class User {
name: String
age: int
}
fn main() {
let users = Array[User]{ User { name: "Ada", age: 36 }, User { name: "Sam", age: 20 } }
let names = users.map(fn(u) { return u.name })
let adults = users.filter(fn(u) { return u.age >= 30 })
let sam = users.find(fn(u) { return u.name == "Sam" }) !? users[0]
let oldest = users.max_by(fn(u) { return u.age }) !? users[0]
let total_age = users.reduce(0, fn(sum, u) { return sum + u.age })
println(names.join(", ")) // Ada, Sam
println(adults.length) // 1
println("%{sam.age} %{oldest.name} %total_age") // 20 Ada 56
println(users.any(fn(u) { return u.age > 30 })) // true
}
| Method | Result |
|---|---|
map(fn) |
New array with each item converted |
filter(fn) |
New array of matching items |
extract(fn) |
Removes matching items and returns them |
find(fn) |
First matching item; throws when none |
any(fn), all(fn) |
bool |
reduce(start, fn) |
Combined value |
min_by(fn), max_by(fn) |
Item with the smallest or largest key |
sum(), min(), max() |
For arrays of numbers |
join(divider) |
Items as one String |
merge(other), copy(), reversed(), unique() |
New arrays |
intersect(other) |
Items present in both |
Sort#
class User {
name: String
age: int
}
fn main() {
let numbers = Array[int]{ 3, 1, 2 }
numbers.sort()
println(numbers.join(",")) // 1,2,3
let descending = numbers.sorted(fn(a, b) { return a < b })
println(descending.join(",")) // 3,2,1
let users = Array[User]{ User { name: "Ada", age: 36 }, User { name: "Sam", age: 20 } }
users.sort_by(fn(u) { return u.age })
println(users[0].name) // Sam
}
sort()orders numbers, strings and tuples ascending. Pass a function that returns true whenabelongs afterbfor another order.sort_by(key)sorts by a value computed per item.sorted,sorted_by,reversedandshuffledreturn a copy;sort,sort_by,reverseandshufflechange the array.- Sorting is stable: equal items keep their order.
Search a sorted array#
fn main() {
let sorted = Array[int]{ 10, 20, 30 }
let found, position = sorted.binary_search(20)
println("%found %position") // true 1
let found2, insert_at = sorted.binary_search(25)
println("%found2 %insert_at") // false 2
}
When the value is missing, the position is where to insert it to keep the order.
Take part of an array#
A range is a start and a length: values[1 .. 2] is two items starting at index 1.
fn main() {
let values = Array[int]{ 10, 20, 30, 40 }
let copy = values[1 .. 2] // new Array: 20, 30
copy[0] = 99
let view = &values[1 .. 2] // view of the same items
view[0] = 21
println(values.join(",")) // 10,21,30,40
println(copy.join(",")) // 99,30
}
values.range(start, length) is the same as the copy form and values.view(start, length) the same as the view form.
Slices#
A slice &[T] reads a sequence without owning it; mut &[T] may also write. A function that takes a slice accepts arrays, fixed arrays, other slices and literals:
fn total(values: local &[int]) int {
let sum = 0
each values as value : sum += value
return sum
}
fn main() {
println(total(Array[int]{ 1, 2, 3 })) // 6
println(total(.{ 4, 5 })) // 9
let buffer = [u8]{ 0 x 1024 } // new writable slice of 1024 zero bytes
println(buffer.length)
}
local means the function only uses the slice during the call. See Borrows & access for the rules, and Files & streams for reading into a buffer.
Fixed arrays#
[T x N] holds exactly N items, without a separate allocation. Its length cannot change:
fn main() {
let point: [int x 3] = { 4, 7, 9 }
point[1] = 8
println(point.length) // 3
println(point[1]) // 8
let filled: [u8 x 8] = { 0... } // repeat the last value to the end
println(filled[7]) // 0
}
Use [T x N]{ ... } where no type is written already, as in let key = [u8 x 2]{ 1, 2 }.
