aiken/dict
A module for working with bytearray dictionaries.
These dictionaries are fundamentally ordered lists of key-value pairs, which preserve some invariants. In particular, each key is only present once in the dictionary.
Types
An opaque Dict
. The type is opaque because the module maintains some
invariant, namely: there’s only one occurrence of a given key in the dictionary.
Note that the key
parameter is a phantom-type, and only present as a
means of documentation. Keys can be any type, yet will need to comparable
to use functions like insert
.
See for example:
pub type Value =
Dict<PolicyId, Dict<AssetName, Int>>
Functions
delete(self: Dict<key, value>, key: key) -> Dict<key, value>
Remove a key-value pair from the dictionary. If the key is not found, no changes are made.
use aiken/int
let result =
dict.new()
|> dict.insert(key: 1, value: 100, compare: int.compare)
|> dict.insert(key: 2, value: 200, compare: int.compare)
|> dict.delete(key: 1)
|> dict.to_list()
result == [(2, 200)]
filter(self: Dict<key, value>, with: fn(key, value) -> Bool) -> Dict<key, value>
Keep only the key-value pairs that pass the given predicate.
use aiken/int
let result =
dict.new()
|> dict.insert(key: 1, value: 100, compare: int.compare)
|> dict.insert(key: 2, value: 200, compare: int.compare)
|> dict.insert(key: 3, value: 300, compare: int.compare)
|> dict.filter(fn(k, _v) { k > 1 })
|> dict.to_list()
result == [(2, 200), (3, 300)]
find(self: Dict<key, value>, value: value) -> Option<key>
Finds a value in the dictionary, and returns the first key found to have that value.
use aiken/bytearray
let foo: ByteArray = #"00"
let bar: ByteArray = #"11"
let baz: ByteArray = #"22"
let result =
dict.new()
|> dict.insert(key: foo, value: 42, compare: bytearray.compare)
|> dict.insert(key: bar, value: 14, compare: bytearray.compare)
|> dict.insert(key: baz, value: 42, compare: bytearray.compare)
|> dict.find(42)
result == Some(foo)
foldl(
self: Dict<key, value>,
zero: result,
with: fn(key, value, result) -> result,
) -> result
Fold over the key-value pairs in a dictionary. The fold direction follows keys in ascending order and is done from left-to-right.
use aiken/int
let result =
dict.new()
|> dict.insert(key: 1, value: 100, compare: int.compare)
|> dict.insert(key: 2, value: 200, compare: int.compare)
|> dict.insert(key: 3, value: 300, compare: int.compare)
|> dict.foldl(0, fn(_k, v, r) { v + r })
result == 600
foldr(
self: Dict<key, value>,
zero: result,
with: fn(key, value, result) -> result,
) -> result
Fold over the key-value pairs in a dictionary. The fold direction follows keys in ascending order and is done from right-to-left.
use aiken/int
let result =
dict.new()
|> dict.insert(key: 1, value: 100, compare: int.compare)
|> dict.insert(key: 2, value: 200, compare: int.compare)
|> dict.insert(key: 3, value: 300, compare: int.compare)
|> dict.foldr(0, fn(_k, v, r) { v + r })
result == 600
from_ascending_list(
xs: List<(key, value)>,
compare: fn(key, key) -> Ordering,
) -> Dict<key, value>
Like ‘from_list’, but from an already sorted list by ascending keys. This function fails (i.e. halt the program execution) if the list isn’t sorted.
use aiken/int
let list = [(1, 100), (2, 200), (3, 300)]
let result =
dict.from_ascending_list(list, int.compare)
|> dict.to_list()
result == [(1, 100), (2, 200), (3, 300)]
This is meant to be used to turn a list constructed off-chain into a Dict
which has taken care of maintaining interval invariants. This function still
performs a sanity check on all keys to avoid silly mistakes. It is, however,
considerably faster than ‘from_list’
from_list(
self: List<(key, value)>,
compare: fn(key, key) -> Ordering,
) -> Dict<key, value>
Construct a dictionary from a list of key-value pairs. Note that when a key is present multiple times, the first occurrence prevails.
use aiken/int
let list = [(1, 100), (3, 300), (2, 200)]
let result =
dict.from_list(list, int.compare)
|> dict.to_list()
result == [(1, 100), (2, 200), (3, 300)]
get(self: Dict<key, value>, key: key) -> Option<value>
Get a value in the dict by its key.
use aiken/bytearray
let foo: ByteArray = #"00"
let result =
dict.new()
|> dict.insert(key: foo, value: "Aiken", compare: bytearray.compare)
|> dict.get(key: foo)
result == Some("Aiken")
has_key(self: Dict<key, value>, key: key) -> Bool
Check if a key exists in the dictionary.
use aiken/bytearray
let foo: ByteArray = #"00"
let result =
dict.new()
|> dict.insert(key: foo, value: "Aiken", compare: bytearray.compare)
|> dict.has_key(foo)
result == True
insert(
self: Dict<key, value>,
key: key,
value: value,
compare: fn(key, key) -> Ordering,
) -> Dict<key, value>
Insert a value in the dictionary at a given key. If the key already exists, its value is overridden. If you need ways to combine keys together, use (insert_with
)[#insert_with].
use aiken/bytearray
let result =
dict.new()
|> dict.insert(key: "foo", value: 1, compare: bytearray.compare)
|> dict.insert(key: "bar", value: 2, compare: bytearray.compare)
|> dict.insert(key: "foo", value: 3, compare: bytearray.compare)
|> dict.to_list()
result == [("bar", 2), ("foo", 3)]
insert_with(
self: Dict<key, value>,
key: key,
value: value,
with: fn(key, value, value) -> Option<value>,
compare: fn(key, key) -> Ordering,
) -> Dict<key, value>
Insert a value in the dictionary at a given key. When the key already exist, the provided merge function is called.
use aiken/bytearray
let sum =
fn (_k, a, b) { Some(a + b) }
let result =
dict.new()
|> dict.insert_with(key: "foo", value: 1, with: sum, compare: bytearray.compare)
|> dict.insert_with(key: "bar", value: 2, with: sum, compare: bytearray.compare)
|> dict.insert_with(key: "foo", value: 3, with: sum, compare: bytearray.compare)
|> dict.to_list()
result == [("bar", 2), ("foo", 4)]
is_empty(self: Dict<key, value>) -> Bool
Efficiently checks whether a dictionary is empty.
dict.is_empty(dict.new()) == True
keys(self: Dict<key, value>) -> List<key>
Extract all the keys present in a given Dict
.
use aiken/bytearray
let foo: ByteArray = #"00"
let bar: ByteArray = #"11"
let result =
dict.new()
|> dict.insert(foo, 14, bytearray.compare)
|> dict.insert(bar, 42, bytearray.compare)
|> dict.insert(foo, 1337, bytearray.compare)
|> dict.keys()
result == [foo, bar]
map(self: Dict<key, a>, with: fn(key, a) -> b) -> Dict<key, b>
Apply a function to all key-value pairs in a map.
use aiken/int
let result =
dict.new()
|> dict.insert(1, 100, int.compare)
|> dict.insert(2, 200, int.compare)
|> dict.insert(3, 300, int.compare)
|> dict.map(fn(_k, v) { v * 2 })
|> dict.to_list()
result == [(1, 200), (2, 400), (3, 600)]
new() -> Dict<key, value>
Create a new map
dict.to_list(dict.new()) == []
size(self: Dict<key, value>) -> Int
Return the number of key-value pairs in the dictionary.
use aiken/int
let result =
dict.new()
|> dict.insert(1, 100, int.compare)
|> dict.insert(2, 200, int.compare)
|> dict.insert(3, 300, int.compare)
|> dict.size()
result == 3
to_list(self: Dict<key, value>) -> List<(key, value)>
Get the inner list holding the dictionary data.
use aiken/int
let result =
dict.new()
|> dict.insert(1, 100, int.compare)
|> dict.insert(2, 200, int.compare)
|> dict.insert(3, 300, int.compare)
|> dict.to_list()
result == [(1, 100), (2, 200), (3, 300)]
union(
left: Dict<key, value>,
right: Dict<key, value>,
compare: fn(key, key) -> Ordering,
) -> Dict<key, value>
Combine two dictionaries. If the same key exist in both the left and right dictionary, values from the left are preferred (i.e. left-biaised).
use aiken/int
let left_dict = dict.from_list([(1, 100), (2, 200)], int.compare)
let right_dict = dict.from_list([(1, 150), (3, 300)], int.compare)
let result =
dict.union(left_dict, right_dict, int.compare) |> dict.to_list()
result == [(1, 100), (2, 200), (3, 300)]
union_with(
left: Dict<key, value>,
right: Dict<key, value>,
with: fn(key, value, value) -> Option<value>,
compare: fn(key, key) -> Ordering,
) -> Dict<key, value>
Like union
but allows specifying the behavior to adopt when a key is present
in both dictionaries. The first value received correspond to the value in the left
dictionnary, whereas the second argument corresponds to the value in the right dictionnary.
When passing None
, the value is removed and not present in the union.
use aiken/int
let left_dict = dict.from_list([(1, 100), (2, 200)], int.compare)
let right_dict = dict.from_list([(1, 150), (3, 300)], int.compare)
let result =
dict.union_with(
left_dict,
right_dict,
fn(_k, v1, v2) { Some(v1 + v2) },
int.compare,
)
|> dict.to_list()
result == [(1, 250), (2, 200), (3, 300)]
values(self: Dict<key, value>) -> List<value>
Extract all the values present in a given Dict
.
use aiken/bytearray
let foo: ByteArray = #"00"
let bar: ByteArray = #"11"
let result =
dict.new()
|> dict.insert(foo, 14, bytearray.compare)
|> dict.insert(bar, 42, bytearray.compare)
|> dict.insert(foo, 1337, bytearray.compare)
|> dict.values()
result == [1337, 42]