LEVIATHAN v962456e · 962456eee1

Standard Library

class Map<K, V>

An associative collection from keys of type K to values of type V, with value semantics.

since 0.1.0-alpha.1linuxwindowswasm

bases
IIterable<Pair<K, V>>

Overview

Like Array, a map is never changed in place: with and without return a new map, and the index assignment m[k] = v rebinds the variable to an updated copy. Entries keep the order in which their keys were first added, and keys, values, entries and for loops all follow that order. Updating the value of an existing key does not move it.

Keys are compared by value for numbers, strings and bool, field by field for structs, and by identity for class instances. Read a value with m[k] or at, which throw when the key is missing; use has, atOrNone or atOr when it might be. for (Pair<K, V> e in m) visits the entries as pairs with first (the key) and second (the value). Printing a map with console.writeln shows it as {key: value, ...}.

Description

Map<K, V> associates keys with values. Like Array, it is a pure value: no method changes the map it is called on. The changing operations return a new map, and the idiom is to rebind the variable. Because get and set are keywords, the vocabulary is at to read, with(key, value) to add or replace, and without(key) to remove. The bracket form m[k] = v is shorthand for m = m.with(k, v), and m[k] reads like m.at(k).

Create an empty map with Map(), or with a declaration that has no initializer, Map<string, int> m;. A map prints as {a: 1, b: 2}.

Order. A map remembers insertion order. keys(), values(), entries(), a for loop and printing all follow it. Replacing the value of a key that is already present keeps the key where it was. Removing a key and adding it again moves it to the end.

Key equality. Primitive keys (int, string, bool, ...) compare by value. A struct key compares field by field, so two separately built Pt(1, 2) values are the same key. A class key compares by identity: two distinct objects are different keys even when their fields match.

Missing keys. at(k) and m[k] throw RuntimeException (with the message key not found: ...) when the key is absent. Use has(k) to test, atOrNone(k) to get a V?, or atOr(k, fallback) to get a default.

Iteration. for (Pair e in m) visits each entry as a Pair, with the key in e.first and the value in e.second, in insertion order. entries() returns the same pairs as an Array.

Building, reading and iterating a map

Map<string, int> m = Map();
m = m.with("b", 2).with("a", 1).with("c", 3);
console.writeln(m);
m = m.with("b", 20);
console.writeln(m);
m = m.without("a");
console.writeln(m);
console.writeln(m.keys());
console.writeln(m.values());
console.writeln(m.has("c"));
console.writeln(m.length());
console.writeln(m.atOr("zz", -1));
console.writeln(m.atOrNone("zz") == None);
console.writeln(m.atOrNone("c"));
m["d"] = 4;
for (Pair e in m) { console.writeln("${e.first}=${e.second}"); }
console.writeln(m);
{b: 2, a: 1, c: 3}
{b: 20, a: 1, c: 3}
{b: 20, c: 3}
[b, c]
[20, 3]
true
2
-1
true
3
b=20
c=3
d=4
{b: 20, c: 3, d: 4}

Rules

  • No method mutates the receiver; with and without return a new map. See lang.collection-value-semantics.
  • m[k] = v is a rebind of the variable m.
  • Iteration, keys, values and entries follow insertion order. Replacing a value keeps its key's position; a removed and re-added key goes to the end.
  • Struct keys are equal field by field; class keys are equal only when they are the same object.
  • at and m[k] throw on a missing key; atOrNone and atOr do not.
  • withAll(other) adds every entry of other, mapValues(f) transforms the values and keeps the keys, and whereEntries(pred) keeps the entries for which pred(key, value) is true. Each returns a new map.

Examples

Struct keys, class keys and bulk operations

struct Pt { int x; int y; }
class Tag { string n; }
Map<Pt, string> byPoint = Map();
byPoint = byPoint.with(Pt(1, 2), "a").with(Pt(1, 2), "b").with(Pt(3, 4), "c");
console.writeln(byPoint.length());
console.writeln(byPoint.at(Pt(1, 2)));
Tag t1 = Tag("k");
Tag t2 = Tag("k");
Map<Tag, int> byTag = Map();
byTag = byTag.with(t1, 1).with(t2, 2).with(t1, 3);
console.writeln(byTag.length());
console.writeln(byTag.at(t1));
Map<string, int> a = Map();
a = a.with("x", 1).with("y", 2).with("z", 3);
console.writeln(a.mapValues((v) => v * 10));
console.writeln(a.whereEntries((k, v) => v > 1));
Map<string, int> extra = Map();
extra = extra.with("z", 0).with("w", 9);
console.writeln(a.withAll(extra));
console.writeln(a.entries().length());
Map<int, string> im = Map();
im = im.with(5, "five").with(1, "one").without(5).with(5, "again");
console.writeln(im);
2
b
2
3
{x: 10, y: 20, z: 30}
{y: 2, z: 3}
{x: 1, y: 2, z: 0, w: 9}
3
{1: one, 5: again}
Map<string, int> ages = Map();
ages = ages.with("ann", 30);
try {
    console.writeln(ages.at("bob"));
} catch (RuntimeException e) {
    console.writeln(e.message);
}
not run — blocked by an open compiler bug: the LLVM engine does not throw on a missing key

The catch block prints key not found: bob.

Notes

A map stored in a class field is rebound like any other variable: index = index.with(k, v);. An Array.groupBy call returns a Map from each key to the array of elements that produced it.

Examples

Counting words

Map<string, int> counts = Map();
for (string w in ["a", "b", "a", "c", "a"]) {
    counts[w] = counts.atOr(w, 0) + 1;
}
console.writeln(counts);
console.writeln(counts.length());
for (Pair<string, int> e in counts) {
    console.writeln("${e.first} -> ${e.second}");
}
{a: 3, b: 1, c: 1}
3
a -> 3
b -> 1
c -> 1

Constructors

new

new()

Create an empty map.

Map<string, int> m; with no initializer is the same empty map.

Examples

An empty map

Map<string, int> m = Map();
console.writeln(m.length());
m["x"] = 1;
console.writeln(m);
0
{x: 1}

Accessors

[]

get [](K key)

The value stored under key, written m[key].

Assigning to a key, m[key] = val, rebinds the variable to an updated copy of the map (the same result as with); other variables that held the old map still see the old value.

Parameters

key
The key to look up.

Throws

RuntimeException
when the map has no entry for key.

Examples

Indexing and index assignment

Map<string, int> a = Map();
a["x"] = 1;
Map<string, int> b = a;
b["x"] = 2;
console.writeln(a["x"]);
console.writeln(b["x"]);
1
2

Methods

at

at(K key) -> V

The value stored under key.

m.at(k) and m[k] are the same operation.

Parameters

key
The key to look up.

Returns

The value for key.

Throws

RuntimeException
when the map has no entry for key.

Examples

Reading a value

Map<string, int> m = Map();
m["a"] = 1;
console.writeln(m.at("a"));
console.writeln(m.has("zz") ? m.at("zz") : -1);
1
-1

A missing key throws

Map<string, int> m = Map();
m["a"] = 1;
try {
    console.writeln(m.at("zz"));
} catch (RuntimeException e) {
    console.writeln("caught: ${e.message}");
}
not run — blocked by an open compiler bug

See also: atOrNone, atOr

atOr

atOr(K key, V dflt) -> V

The value stored under key, or dflt when the key is missing.

The map itself is not changed; the default is not stored.

Parameters

key
The key to look up.
dflt
The value to return when key is not present.

Returns

The stored value, or dflt.

Examples

Counting with a default

Map<string, int> m = Map();
m["a"] = 5;
console.writeln(m.atOr("a", 0));
console.writeln(m.atOr("b", 0));
console.writeln(m.has("b"));
5
0
false

See also: atOrNone

atOrNone

atOrNone(K key) -> V | None

The value stored under key, or None when the key is missing.

Parameters

key
The key to look up.

Returns

The value, or None if there is no entry for key.

Examples

A missing key gives None

Map<string, int> m = Map();
m["a"] = 1;
console.writeln(m.atOrNone("a"));
console.writeln(m.atOrNone("b"));
1
None

See also: at, atOr

entries

entries() -> Array<Pair<K, V>>

The entries as an array of Pair<K, V>, in insertion order.

Each pair has the key as first and the value as second.

Returns

A new array with one pair per entry.

Examples

Entries as pairs

Map<string, int> m = Map();
m["a"] = 1;
m["b"] = 2;
for (Pair<string, int> e in m.entries()) {
    console.writeln("${e.first}: ${e.second}");
}
a: 1
b: 2

has

has(K key) -> bool

Whether the map has an entry for key.

Parameters

key
The key to test.

Returns

true if key is present.

Examples

Testing for a key

Map<string, int> m = Map();
m["a"] = 0;
console.writeln(m.has("a"));
console.writeln(m.has("b"));
true
false

isEmpty

isEmpty() -> bool

Whether the map has no entries.

Returns

true when length() is 0.

Examples

Emptiness

Map<string, int> m = Map();
console.writeln(m.isEmpty());
m["a"] = 1;
console.writeln(m.isEmpty());
true
false

iterator

iterator() -> IIterator<Pair<K, V>>

Return an iterator over the entries as Pair<K, V>, in insertion order.

This is what lets a map be passed where an IIterable<Pair<K, V>> is expected. A for loop over a map does not need it. The iterator walks a snapshot of the map as it was when the iterator was created.

Returns

An iterator positioned before the first entry.

Examples

Walking a map by hand

Map<string, int> m = Map();
m["a"] = 1;
m["b"] = 2;
IIterator<Pair<string, int>> it = m.iterator();
while (it.hasNext()) {
    Pair<string, int> e = it.next();
    console.writeln("${e.first}=${e.second}");
}
a=1
b=2

keys

keys() -> Array<K>

The keys, in the order they were first added.

Returns

A new array of the keys.

Examples

Listing keys

Map<string, int> m = Map();
m["b"] = 2;
m["a"] = 1;
console.writeln(m.keys());
[b, a]

See also: values

length

length() -> int

The number of entries.

Returns

How many keys the map holds.

Examples

Counting entries

Map<string, int> m = Map();
m["a"] = 1;
m["b"] = 2;
m["a"] = 3;
console.writeln(m.length());
2

mapValues

mapValues<U>((V) => U fn) -> Map<K, U>

Return a new map with the same keys whose values are fn applied to the old values.

The keys keep their order. The value type of the result may differ from V. The receiver is not changed.

Parameters

fn
The transformation applied to each value.

Returns

A new map with transformed values.

Examples

Doubling values

Map<string, int> m = Map();
m["a"] = 1;
m["b"] = 2;
console.writeln(m.mapValues((v) => v * 2));
console.writeln(m.mapValues((v) => "n" + v.toString()));
{a: 2, b: 4}
{a: n1, b: n2}

values

values() -> Array<V>

The values, in the same order as keys.

Returns

A new array of the values; element i belongs to key i of keys().

Examples

Listing values

Map<string, int> m = Map();
m["b"] = 2;
m["a"] = 1;
console.writeln(m.values());
[2, 1]

See also: keys

whereEntries

whereEntries((K, V) => bool pred) -> Map<K, V>

Return a new map with only the entries for which pred is true.

The kept entries keep their order. The receiver is not changed.

Parameters

pred
Called with each key and value; the entry is kept when it returns true.

Returns

A new map holding the matching entries.

Examples

Keeping large values

Map<string, int> m = Map();
m["a"] = 1;
m["b"] = 20;
m["c"] = 30;
console.writeln(m.whereEntries((k, v) => v > 10));
console.writeln(m.whereEntries((k, v) => k == "a"));
{b: 20, c: 30}
{a: 1}

with

with(K key, V val) -> Map<K, V>

Return a new map in which key maps to val.

If key is already present its value is replaced and it keeps its position; otherwise the entry is added at the end. The receiver is not changed. The index assignment m[key] = val does the same and rebinds the variable.

Parameters

key
The key to add or update.
val
The value to store.

Returns

A new map with the change applied.

Examples

Adding and replacing

Map<string, int> a = Map();
Map<string, int> b = a.with("x", 1).with("y", 2);
Map<string, int> c = b.with("x", 9);
console.writeln(a);
console.writeln(b);
console.writeln(c);
{}
{x: 1, y: 2}
{x: 9, y: 2}

See also: without

withAll

withAll(Map<K, V> o) -> Map<K, V>

Return a new map holding the entries of this map overlaid with the entries of o.

Where both maps have a key, the value from o wins and the key keeps its position from this map. Keys only in o are added after the existing ones. Neither input is changed.

Parameters

o
The map whose entries are added or take precedence.

Returns

The merged map.

Examples

Merging with overrides

Map<string, int> a = Map();
a["x"] = 1;
a["y"] = 2;
Map<string, int> b = Map();
b["y"] = 20;
b["z"] = 30;
console.writeln(a.withAll(b));
console.writeln(a);
{x: 1, y: 20, z: 30}
{x: 1, y: 2}

without

without(K key) -> Map<K, V>

Return a new map without key.

If key is not present the result is equal to the receiver. The receiver is not changed.

Parameters

key
The key to remove.

Returns

A new map with the entry removed.

Examples

Removing an entry

Map<string, int> m = Map();
m["a"] = 1;
m["b"] = 2;
console.writeln(m.without("a"));
console.writeln(m.without("zz"));
console.writeln(m);
{b: 2}
{a: 1, b: 2}
{a: 1, b: 2}

See also: with

See also

  • Set — A collection of distinct values of type T, with value semantics.
  • Collections are values — Array, Map and Set never change in place; every changing method returns a new collection, and the idiom for change is to rebind.
  • Pair — A pair of two values, possibly of different types.
  • Array — An ordered sequence of values of one type, Array<T>, with value semantics.