Current section
Files
Jump to
Current section
Files
src/gleamy/map.gleam
//// This module provides an implementation of an ordered map data structure based on
//// red-black trees. It associates keys of type `k` with values of type `v`.
//// Keys are ordered by the comparison function.
import gleam/list
import gleam/order.{type Order}
import gleamy/red_black_tree_map as tree
/// The `Map(k, v)` type represents a map that associates keys of type `k`
/// with values of type `v`.
pub type Map(k, v) =
tree.Map(k, v)
/// Creates a new empty map with the provided comparison function for keys.
pub fn new(compare: fn(k, k) -> Order) -> Map(k, v) {
tree.new(compare)
}
/// Inserts a new key-value pair into the map, overwriting the value if the key
/// already exists.
pub fn insert(into map: Map(k, v), key key: k, value value: v) -> Map(k, v) {
tree.insert(map, key, value)
}
/// Get the value associated with a given key in the map, if present.
pub fn get(in map: Map(k, v), key key: k) -> Result(v, Nil) {
tree.find(map, key)
}
/// Checks if the map contains a given key.
pub fn has_key(in map: Map(k, v), key key: k) -> Bool {
case tree.find(map, key) {
Ok(_) -> True
Error(_) -> False
}
}
/// Removes a key-value pair from the map, if the key exists.
pub fn delete(from map: Map(k, v), this key: k) -> Map(k, v) {
tree.delete(map, key)
}
/// Returns the number of key-value pairs in the map.
/// Time complexity: O(n)
pub fn count(map: Map(k, v)) -> Int {
tree.fold(map, 0, fn(a, _, _) { a + 1 })
}
/// Applies a function to every key-value pair in the map, accumulating
/// the results with the provided initial accumulator value.
pub fn fold(
over map: Map(k, v),
from initial: a,
with reducer: fn(a, k, v) -> a,
) -> a {
tree.fold(map, initial, reducer)
}
/// Creates a new map containing only the key-value pairs from the original map
/// that satisfy a given predicate function.
pub fn filter(in map: Map(k, v), for property: fn(k, v) -> Bool) -> Map(k, v) {
tree.fold(map, map, fn(map, k, v) {
case property(k, v) {
True -> map
False -> tree.delete(map, k)
}
})
}
/// Merges two maps into a new map, keeping values from the second map
/// if keys collide.
pub fn merge(intro dict: Map(k, v), from new_entries: Map(k, v)) -> Map(k, v) {
tree.fold(new_entries, dict, fn(a, k, v) { tree.insert(a, k, v) })
}
/// Creates a new map containing only the key-value pairs from the original map
/// where the keys are present in the given list of desired keys.
pub fn take(from map: Map(k, v), keeping desired: List(k)) -> Map(k, v) {
case desired {
[x, ..xs] ->
case tree.find(map, x) {
Ok(v) -> tree.insert(take(map, xs), x, v)
Error(_) -> take(map, xs)
}
[] -> tree.clear(map)
}
}
/// Creates a new map from a list of key-value pairs and a comparison function
/// for keys.
pub fn from_list(
members: List(#(k, v)),
compare: fn(k, k) -> Order,
) -> Map(k, v) {
list.fold(members, tree.new(compare), fn(tree, i) {
tree.insert(tree, i.0, i.1)
})
}
/// Converts the map to a list of key-value pairs.
pub fn to_list(map: Map(k, v)) -> List(#(k, v)) {
tree.foldr(map, [], fn(a, k, v) { [#(k, v), ..a] })
}