README

#Immutable HashMap

A persistent hash map based on hash array mapped tries (HAMT). All operations return new maps, leaving the original unchanged.

#Create

///|
test "create" {
let empty : @hashmap.HashMap[String, Int] = @hashmap.new()
inspect(empty.length(), content="0")
let single = @hashmap.singleton("a", 1)
debug_inspect(single.get("a"), content="Some(1)")
let from_arr = @hashmap.HashMap([("a", 1), ("b", 2)])
inspect(from_arr.length(), content="2")
}

#Add, Get, Remove

add returns a new map with the key-value pair added. remove returns a new map with the key removed.

///|
test "add_get_remove" {
let map = @hashmap.new().add("a", 1).add("b", 2)
debug_inspect(map.get("a"), content="Some(1)")
inspect(map.contains("b"), content="true")
inspect(map["a"], content="1")
let map2 = map.remove("a")
debug_inspect(map2.get("a"), content="None")
// Original map is unchanged
debug_inspect(map.get("a"), content="Some(1)")
}

#Iteration

///|
test "iteration" {
let map = @hashmap.singleton("x", 10)
let sum = map.fold(init=0, (acc, _k, v) => acc + v)
inspect(sum, content="10")
let keys = map.keys().to_array()
debug_inspect(keys, content="[\"x\"]")
let vals = map.values().to_array()
debug_inspect(vals, content="[10]")
}

#Transform and Filter

///|
test "transform" {
let map = @hashmap.HashMap([("a", 1), ("b", 2), ("c", 3)])
let doubled = map.map((_k, v) => v * 2)
debug_inspect(doubled.get("b"), content="Some(4)")
let filtered = map.filter((_k, v) => v > 1)
inspect(filtered.contains("a"), content="false")
inspect(filtered.contains("b"), content="true")
}

#Index Access

Use map["key"] (the at operator) for direct access. Panics if the key is not found.

///|
test "index_access" {
let map = @hashmap.HashMap([("x", 10), ("y", 20)])
@test.assert_eq(map["x"], 10)
@test.assert_eq(map["y"], 20)
}

#Iteration

each iterates over key-value pairs. iter and iter2 return iterators. keys and values return iterators over keys or values only.

///|
test "iteration_full" {
let map = @hashmap.singleton("a", 1)
// each
let buf = []
map.each(fn(k, v) { buf.push((k, v)) })
debug_inspect(buf, content="[(\"a\", 1)]")
// fold
let sum = map.fold(init=0, fn(acc, _k, v) { acc + v })
@test.assert_eq(sum, 1)
// keys / values
debug_inspect(map.keys().to_array(), content="[\"a\"]")
debug_inspect(map.values().to_array(), content="[1]")
// to_array
debug_inspect(map.to_array(), content="[(\"a\", 1)]")
}

#Set Operations

union and intersection combine maps; difference removes keys. By default, union prefers the right map on key conflicts. Use union_with and intersection_with for custom merge logic.

///|
test "set_operations" {
let m1 = @hashmap.HashMap([("a", 1), ("b", 2)])
let m2 = @hashmap.HashMap([("b", 20), ("c", 3)])
// Union prefers right map on conflicts
let u = m1.union(m2)
debug_inspect(u.get("b"), content="Some(20)")
debug_inspect(u.get("c"), content="Some(3)")
// union_with: custom merge function
let u2 = m1.union_with(m2, fn(_k, v1, v2) { v1 + v2 })
debug_inspect(u2.get("b"), content="Some(22)") // 2 + 20
// intersection_with: custom merge
let i = m1.intersection_with(m2, fn(_k, v1, v2) { v1 * v2 })
debug_inspect(i.get("b"), content="Some(40)") // 2 * 20
inspect(i.contains("a"), content="false")
// Difference keeps keys only in left
let d = m1.difference(m2)
debug_inspect(d.get("a"), content="Some(1)")
inspect(d.contains("b"), content="false")
}

#
HashMap

type HashMap[K, V] derive(Eq)

impl Hash for HashMap[K, V]
impl Show for HashMap[K, V]

#
HashMap::HashMap

fn[K : Eq + Hash, V] HashMap::HashMap(arr : ArrayView[(K, V)]) -> HashMap[K, V]

Creates a hash map from an array of key-value pairs.

Example

test {
let m = @hashmap.HashMap([(1, "one"), (2, "two")])
@test.assert_eq(m.get(1), Some("one"))
@test.assert_eq(m.get(2), Some("two"))
}

#
HashMap::add

fn[K : Eq + Hash, V] HashMap::add(self : HashMap[K, V], key : K, value : V) -> HashMap[K, V]

Add a key-value pair to the hashmap.

If a pair with the same key already exists, the old one is replaced

#
HashMap::at

#alias("_[_]")
fn[K : Eq + Hash, V] HashMap::at(self : HashMap[K, V], key : K) -> V

Get value with at access semantics.

#
HashMap::contains

fn[K : Eq + Hash, V] HashMap::contains(self : HashMap[K, V], key : K) -> Bool

Check if the map contains a key.

#
HashMap::difference

fn[K : Eq, V] HashMap::difference(self : HashMap[K, V], other : HashMap[K, V]) -> HashMap[K, V]

Difference of two hashmaps: elements in self but not in other

#
HashMap::each

fn[K, V] HashMap::each(self : HashMap[K, V], f : (K, V) -> Unit raise?) -> Unit raise?

Iterate through the elements in a hash map

#
HashMap::equal

fn[K : Eq, V : Eq] HashMap::equal(HashMap[K, V], HashMap[K, V]) -> Bool

#
HashMap::filter

#alias(filter_with_key, deprecated="`filter_with_key` is deprecated, use `filter` instead")
fn[K, V] HashMap::filter(self : HashMap[K, V], pred : (K, V) -> Bool raise?) -> HashMap[K, V] raise?

Filter entries that satisfy the predicate

#
HashMap::fold

#alias(fold_with_key, deprecated="`fold_with_key` is deprecated, use `fold` instead")
fn[K, V, A] HashMap::fold(self : HashMap[K, V], init~ : A, f : (A, K, V) -> A raise?) -> A raise?

Fold the values in the map with key TODO: can not mark f as #locals(f) because it will be shadowed by the f in the @list.List::fold function TO make it more useful in the future, we may need propagate

#
HashMap::from_array

#deprecated("Use @immut/hashmap.HashMap([...]) instead")
#as_free_fn(of, deprecated="Use @immut/hashmap.HashMap([...]) instead")
#alias(of, deprecated="Use @immut/hashmap.HashMap([...]) instead")
#as_free_fn(deprecated="Use @immut/hashmap.HashMap([...]) instead")
fn[K : Eq + Hash, V] HashMap::from_array(arr : ArrayView[(K, V)]) -> HashMap[K, V]

Creates a hash map from an array of key-value pairs.

#
HashMap::from_iter

#as_free_fn(from_iterator, deprecated="Use HashMap::from_iter instead.")
#alias(from_iterator, deprecated="`from_iterator` is deprecated, use `from_iter` instead")
#as_free_fn
fn[K : Eq + Hash, V] HashMap::from_iter(iter : Iter[(K, V)]) -> HashMap[K, V]

Creates a hash map from an iterator of key-value pairs.

#
HashMap::get

#alias(find, deprecated="`find` is deprecated, use `get` instead")
fn[K : Eq + Hash, V] HashMap::get(self : HashMap[K, V], key : K) -> V?

Lookup a key from a hash map

#
HashMap::hash

fn[K : Hash, V : Hash] HashMap::hash(self : HashMap[K, V]) -> Int

#
HashMap::intersection

fn[K : Eq, V] HashMap::intersection(self : HashMap[K, V], other : HashMap[K, V]) -> HashMap[K, V]

Intersect two hashmaps, right-hand side element is prioritized

#
HashMap::intersection_with

fn[K : Eq, V] HashMap::intersection_with(self : HashMap[K, V], other : HashMap[K, V], f : (K, V, V) -> V raise?) -> HashMap[K, V] raise?

Intersection two hashmaps with a function

#
HashMap::iter

#alias(iterator, deprecated="`iterator` is deprecated, use `iter` instead")
fn[K, V] HashMap::iter(self : HashMap[K, V]) -> Iter[(K, V)]

Converted to Iter

#
HashMap::iter2

#alias(iterator2, deprecated="`iterator2` is deprecated, use `iter2` instead")
fn[K, V] HashMap::iter2(self : HashMap[K, V]) -> Iter2[K, V]

Returns a two-element iterator over key-value pairs.

#
HashMap::keys

fn[K, V] HashMap::keys(self : HashMap[K, V]) -> Iter[K]

Returns all keys of the map

#
HashMap::length

#alias(size, deprecated="`size` is deprecated, use `length` instead")
fn[K, V] HashMap::length(self : HashMap[K, V]) -> Int

Calculate the size of a map.

WARNING: this operation is O(N) in map size

#
HashMap::map

#alias(map_with_key, deprecated="`map_with_key` is deprecated, use `map` instead")
fn[K, V, A] HashMap::map(self : HashMap[K, V], f : (K, V) -> A raise?) -> HashMap[K, A] raise?

Maps over the key-value pairs in the map

#
HashMap::new

#as_free_fn
fn[K, V] HashMap::new() -> HashMap[K, V]

Create a new instance.

#
HashMap::remove

fn[K : Eq + Hash, V] HashMap::remove(self : HashMap[K, V], key : K) -> HashMap[K, V]

Remove an element from a map

#
HashMap::singleton

#as_free_fn
fn[K : Hash, V] HashMap::singleton(key : K, value : V) -> HashMap[K, V]

Create a map with a single key-value pair.

#
HashMap::to_array

fn[K, V] HashMap::to_array(self : HashMap[K, V]) -> Array[(K, V)]

Returns an array of all key-value pairs.

#
HashMap::union

#alias(merge)
fn[K : Eq, V] HashMap::union(self : HashMap[K, V], other : HashMap[K, V]) -> HashMap[K, V]

Union two hashmaps, right-hand side element is prioritized

#
HashMap::union_with

fn[K : Eq, V] HashMap::union_with(self : HashMap[K, V], other : HashMap[K, V], f : (K, V, V) -> V raise?) -> HashMap[K, V] raise?

Union two hashmaps with a function

#
HashMap::values

#alias(elems, deprecated="Use `values` instead")
fn[K, V] HashMap::values(self : HashMap[K, V]) -> Iter[V]

Returns all values of the map