Maps

String-keyed hash maps with `{ }` literals and bracket access.

Maps are string-keyed hash tables. Create them with { "key": value, ... }: keys in literals must be double-quoted strings; values can be any Rain value.

Read and write with map["key"]. Use any string expression as the key, e.g. freq[word] inside a loop. A missing key returns nil instead of raising an error.

Empty maps are written {}. You can build them at runtime with var m = {}; or start from a literal and add keys with m["key"] = value.

Maps nest cleanly: values can be other maps, arrays, or any Rain value. Use bracket access to drill in: outer["inner"]["leaf"].

Call built-in map methods with map->method(): same -> syntax as arrays. Use ->keys(), ->values(), ->has(key), ->delete(key), and ->len() to inspect and mutate maps without writing your own loops.

Iterate a map with **for (key, value von map)**: two names separated by a comma before von. Each pass binds one entry's key and value. An empty map simply skips the loop body.

Literal & access

Create a map with quoted keys, read values with `["key"]`, and add or overwrite entries.

Literal & access
var config = {
    "host": "localhost",
    "port": 5432,
    "debug": true,
    "name": "raindb"
};

print config["host"];
print config["port"];
print config["debug"];
config["port"] = 3306;
print config["port"];
config["newfield"] = "added";
print config["newfield"];
print config["missing"];
output
localhost
5432
true
3306
added
nil

Dynamic keys

Use any string expression as a key: handy for counting or grouping in a loop.

Dynamic keys
var freq = {};
var words = #["apple", "banana", "apple", "cherry", "banana", "apple"];

for (w von words) {
    if (freq[w] == nil) {
        freq[w] = 1;
    } else {
        freq[w] = freq[w] + 1;
    }
}

print freq["apple"];
print freq["banana"];
print freq["cherry"];
output
3
2
1

Iterate with for-von

Loop every key/value pair with `for (key, value von map)`. Order follows hash buckets, not source order.

Iterate with for-von
var scores = {"Alice": 95, "Bob": 87, "Carol": 92};

for (name, score von scores) {
    print "#{name} scored #{score}";
}
output
Carol scored 92
Bob scored 87
Alice scored 95

Empty map

An empty `{}` is valid. A `von` loop over it simply skips the body.

Empty map
var empty = {};

for (k, v von empty) {
    print "never runs";
}

print "done";
output
done

Nested maps and nested von

Maps can hold other maps. Use nested `for (k, v von …)` loops to walk each level.

Nested maps and nested von
var nested = {
    "a": {"x": 1, "y": 2},
    "b": {"p": 9}
};

for (outerKey, inner von nested) {
    print "outer=#{outerKey}";
    for (innerKey, val von inner) {
        print "  #{innerKey}=#{val}";
    }
}
output
outer=a
  y=2
  x=1
outer=b
  p=9

Nested maps and arrays

Combine maps and arrays, e.g. a list of user records, each with its own fields.

Nested maps and arrays
var db = {
    "users": #[
        {"id": 1, "name": "Alice", "scores": #[90, 85, 92]},
        {"id": 2, "name": "Bob",   "scores": #[78, 88, 95]}
    ]
};

for (user von db["users"]) {
    var scores = user["scores"];
    var total = scores#[0] + scores#[1] + scores#[2];
    var avg = total / 3;
    print "#{user["name"]}: avg=#{avg}";
}
output
Alice: avg=89
Bob: avg=87

Building a map in a function

Start with `{}` and fill keys in a loop: useful when keys come from parallel arrays.

Building a map in a function
fun mapFromArrays(keys, vals) {
    var result = {};
    var i = 0;
    while (i < keys->len()) {
        result[keys#[i]] = vals#[i];
        i = i + 1;
    }
    return result;
}

var mapped = mapFromArrays(#["a", "b", "c"], #[1, 2, 3]);
print mapped["a"];
print mapped["b"];
print mapped["c"];
output
1
2
3

Map methods

Use `->` to call built-in helpers: list keys/values, test membership, remove entries, and read the entry count.

Map methods
var m = {"a": 1, "b": 2, "c": 3};

print m->len();
print m->has("a");
print m->has("z");

m->delete("c");
print m->len();
print m->keys();
print m->values();
output
3
true
false
2
#["a", "b"]
#[1, 2]

has() in a frequency counter

Prefer `->has(key)` over `map[key] == nil` when you only need to know if a key exists.

has() in a frequency counter
var freq = {};
var words = #["apple", "banana", "apple", "cherry"];

for (w von words) {
    if (freq->has(w)) {
        freq[w] = freq[w] + 1;
    } else {
        freq[w] = 1;
    }
}

print freq->len();
print freq->has("apple");
print freq["apple"];
output
3
true
2

Map methods

Call built-in methods with `->`. `keys()` and `values()` return new arrays; order follows the map's hash buckets (same as `for (k, v von map)`).

SymbolDescriptionExample
->len()Entry count
var m = {"a": 1, "b": 2}; print m->len();
->keys()All keys as an array
var m = {"x": 1, "y": 2}; print m->keys();
->values()All values as an array
var m = {"x": 1, "y": 2}; print m->values();
->has(key)Whether key exists (string)
var m = {"a": 1}; print m->has("a"); print m->has("z");
->delete(key)Remove key; returns nil
var m = {"a": 1, "b": 2}; m->delete("a"); print m->len();

Notes