Data & Control

Collections & Comprehensions

Choose Array, Map, or Set and transform them with canonical comprehensions.

Choose a collection from the behavior your program must preserve: position and repetition, lookup by key, or uniqueness. Comprehensions then provide a compact way to filter and transform those collections without changing their ordering rules.

Choose the collection first

CollectionChoose it forObservable behavior
Array<T>Ordered items, positional access, and repeated valuesIterates by increasing index and keeps duplicates
Map<K, V>Values selected by a keyKeys keep insertion order; updating an existing key keeps its slot
Set<T>Unique valuesThe first equal value keeps the insertion slot

Run one example

Save this as collections-comprehensions.tpz:

TOPAZ
let scores = [10, 25, 10]
let labels = map { "Ada": 10, "Lin": 25 }
let unique = set { 10, 25, 10 }
let focused = [ for score in scores if score >= 20 => score * 2 ]

let first = scores[0]
let missing = scores.get(9)
let hasAda = "Ada" in labels.keys
let missingLabel = match missing {
    case Some(value) => "found {value}"
    case None => "missing"
}

print("{scores}:{unique.toArray()}:{labels.keys}")
print("{focused}:{first}:{hasAda}")
print(missingLabel)
BASH
topaz check collections-comprehensions.tpz
topaz run collections-comprehensions.tpz

It prints:

Output
[10, 25, 10]:[10, 25]:[Ada, Lin]
[50]:10:true
missing

The array keeps both 10 values. The set collapses the second 10 and keeps the first insertion order. labels.keys is an insertion-order array, so membership is written "Ada" in labels.keys.

Read and change collections deliberately

scores[0] is a direct indexed read. A negative or out-of-range index stops with a runtime fault. scores.get(9) is the non-faulting choice and returns Option, which the example handles with match.

In-place mutation requires a mutable root binding: begin with let mut values = [...] before calling a mutating operation such as values.push(...). A nonmutating expression may still create a new collection from an immutable binding.

Map duplicate handling differs from Set handling. A repeated simple literal key is a static error. If two keys become equal only at runtime, map construction evaluates the operands and then faults instead of overwriting. Map.insert is the explicit operation for adding or updating a key.

Literal, loop, or comprehension?

  • Use [a, b], set { a, b }, or map { key: value } when the elements are written directly.
  • Use for item in source { ... } when the body is easiest to read as repeated steps. In statement position it is for effects; in expression position it collects body results into an Array.
  • Use [ for item in source if condition => result ] when filtering and transformation form one clear expression. Replace the outer brackets with set { ... } for unique results or map { ... } for key/value results.

Comprehension clauses begin with for, continue with for or if without commas, and finish with =>. Clauses nest from left to right. The final collection becomes visible only after every reached clause and body succeeds.

Common mistakes

The collection types are Array<T>, Map<K, V>, and Set<T>; [T] is not a collection type. Set and map literals require the words set and map#{...} and a bare {key: value} are not their syntax.

key in map is invalid. Use key in map.keys. A refutable pattern mismatch in a comprehension is a fault, not an automatic filter; write an explicit if clause to skip items.

Exact boundaries

  • Array spread accepts another Array only. Set and map literals and comprehensions have no spread form.
  • Empty set {} and map {} need an expected Set<T> or Map<K, V> type.
  • Map keys and set elements must be recursively keyable.
  • Removing an item removes its order slot; reinserting it appends a new slot. Updating an existing map value preserves key order.
  • for can iterate Array, integer ranges, Set, and map.keys. Strings require an explicit scalar operation.

User-defined iteration, generators, lazy or parallel comprehensions, iterable spread, and unordered collection semantics are not part of the current language.

Return to the course example in Data and Control. See Patterns & Control Flow for comprehension bindings and Collection Operations for the exact everyday methods.