Maps and Sets
Maps
A map associates keys with values. The literal requires the # prefix —
without it the compiler interprets the braces as a block of statements:
#{} literal, procedural Map::new API, iterating over keys, and word counting.
02-maps.zolo
// Feature: Maps — key/value (hash table)
// Syntax: literal `#{"key": value}`, or `Map::new()` + `Map.set/get`
// When to use: dictionary, key lookup, configs, records.
use std::Map
// Map literal — note the leading `#`.
let user = #{name: "Alice", age: 30, active: true}
// Access by key: brackets always, dot when the key is
// a valid identifier.
print(user["name"]) // Alice
print(user.age) // 30
print(user["active"]) // true
// Arbitrary keys with quotes.
let labels = #{"user-id": 42, "x-trace": "abc"}
print(labels["user-id"]) // 42
print(labels["x-trace"]) // abc
// Procedural API: create, set, get, has, remove.
let m = Map::new()
m.set("host", "localhost")
m.set("port", "8080")
print(m.get("host")) // localhost
print(m.has("port")) // true
print(m.has("missing")) // false
// Iterating over keys/values.
// `#{...}` is a plain map literal (table). To use the Map.* helpers
// that need a Map object, build it with `Map::from(literal)`.
let scores_lit = #{math: 95, science: 87, english: 92}
let scores = Map::from(scores_lit)
let keys = scores.keys()
for k in keys {
let v = scores.get(k)
print("{k} = {v}")
}
// Size.
print(scores.keys().len()) // 3
// Remove a key.
let cfg = Map::new()
cfg.set("a", "1")
cfg.set("b", "2")
cfg.remove("a")
print(cfg.keys()) // [b]
// Maps are great for counters.
let counter = Map::new()
let words = ["foo", "bar", "foo", "baz", "foo", "bar"]
for w in words {
if counter.has(w) {
counter.set(w, counter.get(w) + 1)
} else {
counter.set(w, 1)
}
}
print(counter.get("foo")) // 3
print(counter.get("bar")) // 2
Things to keep in mind:
- Keys that are valid identifiers can be accessed with
.or[]; keys with hyphens or spaces require[]. - To use
Map.*methods (such as.keys(),.get()) on a literal, convert it first withMap::from(literal).
Sets
A Set is a collection without duplicates and with no guaranteed order.
Ideal for membership tests and deduplication:
Set::new(), add, has, array deduplication, and manual intersection.
10-sets.zolo
// Feature: Sets — collection without duplicates
// Syntax: `Set::new()` + `Set.add/has/len/is_empty`
// When to use: deduplication, membership tests, intersection/union
// when order doesn't matter.
use std::Set
// Create an empty set.
let s = Set::new()
s.add("a")
s.add("b")
s.add("a") // duplicate: ignored
print(s.len()) // 2
print(s.has("a")) // true
print(s.has("c")) // false
print(s.is_empty()) // false
// Empty set.
let empty = Set::new()
print(empty.is_empty()) // true
print(empty.len()) // 0
// Set with integers.
let nums = Set::new()
nums.add(1)
nums.add(2)
nums.add(3)
nums.add(2) // dup
nums.add(1) // dup
print(nums.len()) // 3
// Deduplicate an array.
fn dedup(arr: [int]) -> int {
let s = Set::new()
for x in arr {
s.add(x)
}
return s.len()
}
print(dedup([1, 2, 3, 2, 1, 4, 3, 5])) // 5
// Manual intersection via Set.has.
let a = Set::new()
a.add("x")
a.add("y")
a.add("z")
let b = Set::new()
b.add("y")
b.add("z")
b.add("w")
let common = Set::new()
let candidates = ["x", "y", "z", "w"]
for c in candidates {
if a.has(c) && b.has(c) {
common.add(c)
}
}
print(common.len()) // 2 (y, z)
print(common.has("y")) // true
print(common.has("x")) // false
Challenge
Create two maps #{a: 1, b: 2} and #{b: 3, c: 4}, convert both to
Map, and print the keys that appear in both using a Set.
See also