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_ascending_list_with(
  xs: List<(key, value)>,
  compare: fn(key, key) -> Ordering,
  value_predicate: fn(value) -> Bool,
) -> Dict<key, value>

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]
Search Document