Skip to content

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
Playground
// 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 with Map::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
Playground
// 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

enespt-br