aiken/collection/pairs
A module for working with associative lists (a.k.a Pairs).
While any function that works on List also works on Pairs, this module provides some extra helpers
that are specifically tailored to working with associative lists. Fundamentally, a Pairs<key, value> is
a type-alias to List<Pair<key, value>>.
Unlike dictionaries (a.k.a.
Dict, associative lists make no assumption about the ordering of elements within the list. As a result, lookup functions do traverse the entire list when invoked. They are also not sets, and thus allow for duplicate keys. This is reflected in the functions used to interact with them.
Functions
Inspecting
Get all values in the alist associated with a given key.
pairs.get_all([], "a") == []
pairs.get_all([Pair("a", 1)], "a") == [1]
pairs.get_all([Pair("a", 1), Pair("b", 2)], "a") == [1]
pairs.get_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [1, 3]
Get the value in the alist by its key.
If multiple values with the same key exist, only the first one is returned.
pairs.get_first([], "a") == None
pairs.get_first([Pair("a", 1)], "a") == Some(1)
pairs.get_first([Pair("a", 1), Pair("b", 2)], "a") == Some(1)
pairs.get_first([Pair("a", 1), Pair("b", 2)], "c") == None
pairs.get_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(1)
Get the value in the alist by its key.
If multiple values with the same key exist, only the last one is returned.
pairs.get_last([], "a") == None
pairs.get_last([Pair("a", 1)], "a") == Some(1)
pairs.get_last([Pair("a", 1), Pair("b", 2)], "a") == Some(1)
pairs.get_last([Pair("a", 1), Pair("b", 2)], "c") == None
pairs.get_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(3)
Finds all keys in the alist associated with a given value.
pairs.find_all([], 1) == []
pairs.find_all([Pair("a", 1)], 1) == ["a"]
pairs.find_all([Pair("a", 1), Pair("b", 2)], 1) == ["a"]
pairs.find_all([Pair("a", 1), Pair("b", 2)], 3) == []
pairs.find_all([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == ["a", "c"]
Finds the first key in the alist associated with a given value, if any.
pairs.find_first([], 1) == None
pairs.find_first([Pair("a", 1)], 1) == Some("a")
pairs.find_first([Pair("a", 1), Pair("b", 2)], 1) == Some("a")
pairs.find_first([Pair("a", 1), Pair("b", 2)], 3) == None
pairs.find_first([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("a")
Finds the last key in the alist associated with a given value, if any.
pairs.find_last([], 1) == None
pairs.find_last([Pair("a", 1)], 1) == Some("a")
pairs.find_last([Pair("a", 1), Pair("b", 2)], 1) == Some("a")
pairs.find_last([Pair("a", 1), Pair("b", 2)], 3) == None
pairs.find_last([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("c")
Check if a key exists in the pairs.
pairs.has_key([], "a") == False
pairs.has_key([Pair("a", 1)], "a") == True
pairs.has_key([Pair("a", 1), Pair("b", 2)], "a") == True
pairs.has_key([Pair("a", 1), Pair("b", 2)], "c") == False
pairs.has_key([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == True
Extract all the keys present in a given Pairs.
pairs.keys([]) == []
pairs.keys([Pair("a", 1)]) == ["a"]
pairs.keys([Pair("a", 1), Pair("b", 2)]) == ["a", "b"]
pairs.keys([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == ["a", "b", "a"]
Extract all the values present in a given Pairs.
pairs.values([]) == []
pairs.values([Pair("a", 1)]) == [1]
pairs.values([Pair("a", 1), Pair("b", 2)]) == [1, 2]
pairs.values([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == [1, 2, 3]
Inspecting Forcibly
More efficient version of get_first which fails if no key is found.
pairs.expect_get_first([], "a") β π₯
pairs.expect_get_first([Pair("a", 1)], "a") == 1
pairs.expect_get_first([Pair("a", 1), Pair("b", 2)], "a") == 1
pairs.expect_get_first([Pair("a", 1), Pair("b", 2)], "c") == β π₯
pairs.expect_get_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == 1
More efficient version of get_last which fails if no key is found.
pairs.expect_get_last([], "a") β π₯
pairs.expect_get_last([Pair("a", 1)], "a") == 1
pairs.expect_get_last([Pair("a", 1), Pair("b", 2)], "a") == 1
pairs.expect_get_last([Pair("a", 1), Pair("b", 2)], "c") β π₯
pairs.expect_get_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == 3
More efficient version of find_first which fails if no element is found.
pairs.expect_find_first([], 1) β π₯
pairs.expect_find_first([Pair("a", 1)], 1) == "a"
pairs.expect_find_first([Pair("a", 1), Pair("b", 2)], 1) == "a"
pairs.expect_find_first([Pair("a", 1), Pair("b", 2)], 3) β π₯
pairs.expect_find_first([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == "a"
More efficient version of find_last which fails if no element is found.
pairs.expect_find_last([], 1) β π₯
pairs.expect_find_last([Pair("a", 1)], 1) == "a"
pairs.expect_find_last([Pair("a", 1), Pair("b", 2)], 1) == "a"
pairs.expect_find_last([Pair("a", 1), Pair("b", 2)], 3) β π₯
pairs.expect_find_last([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == "c"
More efficient version of has_key, which fails if the key isnβt present in the associative list.
pairs.expect_has_key([], "a") β π₯
pairs.expect_has_key([Pair("a", 1)], "a") β β
pairs.expect_has_key([Pair("a", 1), Pair("b", 2)], "a") β β
pairs.expect_has_key([Pair("a", 1), Pair("b", 2)], "c") β π₯
pairs.expect_has_key([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") β β
Modifying
Remove all key-value pairs matching the key from the Pairs. If the key is not found, no changes are made.
pairs.delete_all([], "a") == []
pairs.delete_all([Pair("a", 1)], "a") == []
pairs.delete_all([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.delete_all([Pair("a", 1), Pair("b", 2)], "c") == [Pair("a", 1), Pair("b", 2)]
pairs.delete_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2)]
Remove a single key-value pair from the Pairs. If the key is not found, no changes are made.
Duplicate keys are not deleted. Only the first key found is deleted.
pairs.delete_first([], "a") == []
pairs.delete_first([Pair("a", 1)], "a") == []
pairs.delete_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.delete_first([Pair("a", 1), Pair("b", 2)], "c") == [Pair("a", 1), Pair("b", 2)]
pairs.delete_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)]
Remove a single key-value pair from the Pairs. If the key is not found, no changes are made.
Duplicate keys are not deleted. Only the last key found is deleted.
pairs.delete_last([], "a") == []
pairs.delete_last([Pair("a", 1)], "a") == []
pairs.delete_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.delete_last([Pair("a", 1), Pair("b", 2)], "c") == [Pair("a", 1), Pair("b", 2)]
pairs.delete_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)]
insert_by_ascending_key(
self: Pairs<key, value>,
key: key,
value: value,
compare: fn(key, key) -> Ordering,
) -> Pairs<key, value>
Insert a value in the Pairs at a given key. If the key already exists,
the value is added in front.
The list is only traversed up to the given key and the traversal
stops as soon as a higher key is encountered. Said differently, the list
is assumed to be ordered by ascending keys! If it is not, expect the
unexpected.
use aiken/primitive/bytearray
[Pair("bar", 2), Pair("foo", 3), Pair("foo", 1)] == ([]
|> pairs.insert_by_ascending_key(key: "foo", value: 1, compare: bytearray.compare)
|> pairs.insert_by_ascending_key(key: "bar", value: 2, compare: bytearray.compare)
|> pairs.insert_by_ascending_key(key: "foo", value: 3, compare: bytearray.compare)
)
insert_with_by_ascending_key(
self: Pairs<key, value>,
key: key,
value: value,
compare: fn(key, key) -> Ordering,
with: fn(value, value) -> value,
) -> Pairs<key, value>
Like insert_by_ascending_key but specifies
how to combine two values on a key conflict.
The list is only traversed up to the given key and the traversal
stops as soon as a higher key is encountered. Said differently, the list
is assumed to be ordered by ascending keys! If it is not, expect the
unexpected.
use aiken/primitive/bytearray
let add_integer = fn(x, y) { x + y }
[Pair("bar", 2), Pair("foo", 4)] == ([]
|> pairs.insert_with_by_ascending_key(key: "foo", value: 1, compare: bytearray.compare, with: add_integer)
|> pairs.insert_with_by_ascending_key(key: "bar", value: 2, compare: bytearray.compare, with: add_integer)
|> pairs.insert_with_by_ascending_key(key: "foo", value: 3, compare: bytearray.compare, with: add_integer)
)
Apply a function to all key-value pairs in a alist, replacing the values.
[Pair("a", 200), Pair("b", 400)] == ([Pair("a", 100), Pair("b", 200)]
|> pairs.map(, fn(_k, v) { v * 2 })
)
pop_until(
self: Pairs<key, value>,
until: fn(key, value) -> Bool,
) -> (Option<Pair<key, value>>, Pairs<key, value>)
Drop elements from an associative list until a predicate is satisfied.
Returns the first key/value pair that satisfies the predicate, and the rest
of the list after that key/value pair.
let predicate = fn(k, v) { k == "a" && v > 1 }
expect (None, []) = pairs.pop_until([], predicate)
expect (None, []) = pairs.pop_until([Pair("a", 1), Pair("b", 2)], predicate)
expect (Some(Pair("a", 3), []) = pairs.pop_until([Pair("a", 1), Pair("b", 2), Pair("a", 3)], predicate)
pop_until_and_then(
self: Pairs<key, value>,
until: fn(key, value) -> Bool,
return: fn(Option<Pair<key, value>>, Pairs<key, value>) -> result,
) -> result
Like pop_until but leverages backpassing.
let predicate = fn(k, v) { k == "a" && v > 1 }
expect None, [] <- pairs.pop_until_and_then([], predicate)
expect None, [] <- pairs.pop_until_and_then([Pair("a", 1), Pair("b", 2)], predicate)
expect Some(Pair("a", 3), [] <- pairs.pop_until_and_then([Pair("a", 1), Pair("b", 2), Pair("a", 3)], predicate)
Drop elements from an associative list until a given key is encountered.
Returns the first value at that key (if any), and the rest of the list after
that key/value pair.
expect (None, []) = pairs.pop_until_key([], "a")
expect (Some(1), [Pair("b", 2)]) = pairs.pop_until_key([Pair("a", 1), Pair("b", 2)], "a")
expect (Some(3), []) = pairs.pop_until_key([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "c")
expect (None, []) = pairs.pop_until_key([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "")
pop_until_key_and_then(
self: Pairs<key, value>,
until: key,
return: fn(Option<value>, Pairs<key, value>) -> result,
) -> result
A version of pop_until_key which leverages backpassing.
expect None, [] <- pairs.pop_until_key_and_then([], "a")
expect Some(1), [Pair("b", 2)] <- pairs.pop_until_key_and_then([Pair("a", 1), Pair("b", 2)], "a")
expect Some(3), [] <- pairs.pop_until_key_and_then([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "c")
expect None, [] <- pairs.pop_until_key_and_then([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "")
repsert_by_ascending_key(
self: Pairs<key, value>,
key: key,
value: value,
compare: fn(key, key) -> Ordering,
) -> Pairs<key, value>
Insert a value in the Pairs at a given key. If the key already exists,
its value is replaced.
The list is only traversed up to the given key and the traversal
stops as soon as a higher key is encountered. Said differently, the list
is assumed to be ordered by ascending keys! If it is not, expect the
unexpected.
use aiken/primitive/bytearray
[Pair("bar", 2), Pair("foo", 3)] == ([]
|> pairs.repsert_by_ascending_key(key: "foo", value: 1, compare: bytearray.compare)
|> pairs.repsert_by_ascending_key(key: "bar", value: 2, compare: bytearray.compare)
|> pairs.repsert_by_ascending_key(key: "foo", value: 3, compare: bytearray.compare)
)
Modifying Forcibly
More efficient version of delete_first, which fails if
thereβs no matching element to delete.
pairs.expect_delete_first([], "a") β π₯
pairs.expect_delete_first([Pair("a", 1)], "a") == []
pairs.expect_delete_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.expect_delete_first([Pair("a", 1), Pair("b", 2)], "c") β π₯
pairs.expect_delete_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)]
More efficient version of delete_last, which fails if
thereβs no matching element to delete.
pairs.expect_delete_last([], "a") β π₯
pairs.expect_delete_last([Pair("a", 1)], "a") == []
pairs.expect_delete_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.expect_delete_last([Pair("a", 1), Pair("b", 2)], "c") β π₯
pairs.expect_delete_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)]
expect_pop_until(
self: Pairs<key, value>,
until: fn(key, value) -> Bool,
) -> (Pair<key, value>, Pairs<key, value>)
More efficient version of pop_until, which fails if thereβs
no element matching the predicate.
let predicate = fn(k, v) { k == "a" && v > 1 }
π₯ = pairs.expect_pop_until([], predicate)
π₯ = pairs.expect_pop_until([Pair("a", 1), Pair("b", 2)], predicate)
expect (Pair("a", 3), []) = pairs.expect_pop_until([Pair("a", 1), Pair("b", 2), Pair("a", 3)], predicate)
expect_pop_until_and_then(
self: Pairs<key, value>,
until: fn(key, value) -> Bool,
return: fn(Pair<key, value>, Pairs<key, value>) -> result,
) -> result
A version of expect_pop_until which leverages backpassing.
let predicate = fn(k, v) { k == "a" && v > 1 }
π₯ <- pairs.expect_pop_until_and_then([], predicate)
π₯ <- pairs.expect_pop_until([Pair("a", 1), Pair("b", 2)], predicate)
expect Pair("a", 3), [] <- pairs.expect_pop_until_and_then([Pair("a", 1), Pair("b", 2), Pair("a", 3)], predicate)
More efficient version of pop_until_key which fails if the key isnβt found.
π₯ = pairs.expect_pop_until_key([], "a")
expect (1, [Pair("b", 2)]) = pairs.expect_pop_until_key([Pair("a", 1), Pair("b", 2)], "a")
expect (3, []) = pairs.expect_pop_until_key([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "c")
π₯ = pairs.expect_pop_until_key([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "")
expect_pop_until_key_and_then(
self: Pairs<key, value>,
until: key,
return: fn(value, Pairs<key, value>) -> result,
) -> result
A version of expect_pop_until_key which leverages backpassing.
π₯ <- pairs.expect_pop_until_key_and_then([], "a")
expect 1, [Pair("b", 2)] <- pairs.expect_pop_until_key_and_then([Pair("a", 1), Pair("b", 2)], "a")
expect 3, [] <- pairs.expect_pop_until_key_and_then([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "c")
π₯ <- pairs.expect_pop_until_key_and_then([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "")
Transforming
Fold over the key-value pairs in a pairs. The fold direction follows keys
in ascending order and is done from left-to-right.
1400 == ([Pair(1, 100), Pair(2, 200), Pair(3, 300)]
|> pairs.foldl(0, fn(k, v, result) { k * v + result })
)
use aiken/primitive/bytearray.{concat}
"a1b2c3" == ([Pair("a", "1"), Pair("b", "2"), Pair("c", "3")]
|> pairs.foldl("", fn(k, v, str) { concat(str, concat(k, v)) })
)
Fold over the key-value pairs in a Pairs. The fold direction follows the
order of elements in the Pairs and is done from right-to-left.
1400 == ([Pair(1, 100), Pair(2, 200), Pair(3, 300)]
|> pairs.foldr(0, fn(k, v, result) { k * v + result })
)
use aiken/primitive/bytearray.{concat}
"c3b2a1" == ([Pair("a", "1"), Pair("b", "2"), Pair("c", "3")]
|> pairs.foldr("", fn(k, v, str) { concat(str, concat(k, v)) })
)
Get all values in the alist associated with a given key.
pairs.get_all([], "a") == []
pairs.get_all([Pair("a", 1)], "a") == [1]
pairs.get_all([Pair("a", 1), Pair("b", 2)], "a") == [1]
pairs.get_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [1, 3]
Get the value in the alist by its key. If multiple values with the same key exist, only the first one is returned.
pairs.get_first([], "a") == None
pairs.get_first([Pair("a", 1)], "a") == Some(1)
pairs.get_first([Pair("a", 1), Pair("b", 2)], "a") == Some(1)
pairs.get_first([Pair("a", 1), Pair("b", 2)], "c") == None
pairs.get_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(1)
Get the value in the alist by its key. If multiple values with the same key exist, only the last one is returned.
pairs.get_last([], "a") == None
pairs.get_last([Pair("a", 1)], "a") == Some(1)
pairs.get_last([Pair("a", 1), Pair("b", 2)], "a") == Some(1)
pairs.get_last([Pair("a", 1), Pair("b", 2)], "c") == None
pairs.get_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(3)
Finds all keys in the alist associated with a given value.
pairs.find_all([], 1) == []
pairs.find_all([Pair("a", 1)], 1) == ["a"]
pairs.find_all([Pair("a", 1), Pair("b", 2)], 1) == ["a"]
pairs.find_all([Pair("a", 1), Pair("b", 2)], 3) == []
pairs.find_all([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == ["a", "c"]
Finds the first key in the alist associated with a given value, if any.
pairs.find_first([], 1) == None
pairs.find_first([Pair("a", 1)], 1) == Some("a")
pairs.find_first([Pair("a", 1), Pair("b", 2)], 1) == Some("a")
pairs.find_first([Pair("a", 1), Pair("b", 2)], 3) == None
pairs.find_first([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("a")
Finds the last key in the alist associated with a given value, if any.
pairs.find_last([], 1) == None
pairs.find_last([Pair("a", 1)], 1) == Some("a")
pairs.find_last([Pair("a", 1), Pair("b", 2)], 1) == Some("a")
pairs.find_last([Pair("a", 1), Pair("b", 2)], 3) == None
pairs.find_last([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("c")
Check if a key exists in the pairs.
pairs.has_key([], "a") == False
pairs.has_key([Pair("a", 1)], "a") == True
pairs.has_key([Pair("a", 1), Pair("b", 2)], "a") == True
pairs.has_key([Pair("a", 1), Pair("b", 2)], "c") == False
pairs.has_key([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == True
Extract all the keys present in a given Pairs.
pairs.keys([]) == []
pairs.keys([Pair("a", 1)]) == ["a"]
pairs.keys([Pair("a", 1), Pair("b", 2)]) == ["a", "b"]
pairs.keys([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == ["a", "b", "a"]
Extract all the values present in a given Pairs.
pairs.values([]) == []
pairs.values([Pair("a", 1)]) == [1]
pairs.values([Pair("a", 1), Pair("b", 2)]) == [1, 2]
pairs.values([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == [1, 2, 3]
More efficient version of get_first which fails if no key is found.
pairs.expect_get_first([], "a") β π₯
pairs.expect_get_first([Pair("a", 1)], "a") == 1
pairs.expect_get_first([Pair("a", 1), Pair("b", 2)], "a") == 1
pairs.expect_get_first([Pair("a", 1), Pair("b", 2)], "c") == β π₯
pairs.expect_get_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == 1
More efficient version of get_last which fails if no key is found.
pairs.expect_get_last([], "a") β π₯
pairs.expect_get_last([Pair("a", 1)], "a") == 1
pairs.expect_get_last([Pair("a", 1), Pair("b", 2)], "a") == 1
pairs.expect_get_last([Pair("a", 1), Pair("b", 2)], "c") β π₯
pairs.expect_get_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == 3
More efficient version of find_first which fails if no element is found.
pairs.expect_find_first([], 1) β π₯
pairs.expect_find_first([Pair("a", 1)], 1) == "a"
pairs.expect_find_first([Pair("a", 1), Pair("b", 2)], 1) == "a"
pairs.expect_find_first([Pair("a", 1), Pair("b", 2)], 3) β π₯
pairs.expect_find_first([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == "a"
More efficient version of find_last which fails if no element is found.
pairs.expect_find_last([], 1) β π₯
pairs.expect_find_last([Pair("a", 1)], 1) == "a"
pairs.expect_find_last([Pair("a", 1), Pair("b", 2)], 1) == "a"
pairs.expect_find_last([Pair("a", 1), Pair("b", 2)], 3) β π₯
pairs.expect_find_last([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == "c"
More efficient version of has_key, which fails if the key isnβt present in the associative list.
pairs.expect_has_key([], "a") β π₯
pairs.expect_has_key([Pair("a", 1)], "a") β β
pairs.expect_has_key([Pair("a", 1), Pair("b", 2)], "a") β β
pairs.expect_has_key([Pair("a", 1), Pair("b", 2)], "c") β π₯
pairs.expect_has_key([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") β β
Modifying
Remove all key-value pairs matching the key from the Pairs. If the key is not found, no changes are made.
pairs.delete_all([], "a") == []
pairs.delete_all([Pair("a", 1)], "a") == []
pairs.delete_all([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.delete_all([Pair("a", 1), Pair("b", 2)], "c") == [Pair("a", 1), Pair("b", 2)]
pairs.delete_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2)]
Remove a single key-value pair from the Pairs. If the key is not found, no changes are made.
Duplicate keys are not deleted. Only the first key found is deleted.
pairs.delete_first([], "a") == []
pairs.delete_first([Pair("a", 1)], "a") == []
pairs.delete_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.delete_first([Pair("a", 1), Pair("b", 2)], "c") == [Pair("a", 1), Pair("b", 2)]
pairs.delete_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)]
Remove a single key-value pair from the Pairs. If the key is not found, no changes are made.
Duplicate keys are not deleted. Only the last key found is deleted.
pairs.delete_last([], "a") == []
pairs.delete_last([Pair("a", 1)], "a") == []
pairs.delete_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.delete_last([Pair("a", 1), Pair("b", 2)], "c") == [Pair("a", 1), Pair("b", 2)]
pairs.delete_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)]
insert_by_ascending_key(
self: Pairs<key, value>,
key: key,
value: value,
compare: fn(key, key) -> Ordering,
) -> Pairs<key, value>
Insert a value in the Pairs at a given key. If the key already exists,
the value is added in front.
The list is only traversed up to the given key and the traversal
stops as soon as a higher key is encountered. Said differently, the list
is assumed to be ordered by ascending keys! If it is not, expect the
unexpected.
use aiken/primitive/bytearray
[Pair("bar", 2), Pair("foo", 3), Pair("foo", 1)] == ([]
|> pairs.insert_by_ascending_key(key: "foo", value: 1, compare: bytearray.compare)
|> pairs.insert_by_ascending_key(key: "bar", value: 2, compare: bytearray.compare)
|> pairs.insert_by_ascending_key(key: "foo", value: 3, compare: bytearray.compare)
)
insert_with_by_ascending_key(
self: Pairs<key, value>,
key: key,
value: value,
compare: fn(key, key) -> Ordering,
with: fn(value, value) -> value,
) -> Pairs<key, value>
Like insert_by_ascending_key but specifies
how to combine two values on a key conflict.
The list is only traversed up to the given key and the traversal
stops as soon as a higher key is encountered. Said differently, the list
is assumed to be ordered by ascending keys! If it is not, expect the
unexpected.
use aiken/primitive/bytearray
let add_integer = fn(x, y) { x + y }
[Pair("bar", 2), Pair("foo", 4)] == ([]
|> pairs.insert_with_by_ascending_key(key: "foo", value: 1, compare: bytearray.compare, with: add_integer)
|> pairs.insert_with_by_ascending_key(key: "bar", value: 2, compare: bytearray.compare, with: add_integer)
|> pairs.insert_with_by_ascending_key(key: "foo", value: 3, compare: bytearray.compare, with: add_integer)
)
Apply a function to all key-value pairs in a alist, replacing the values.
[Pair("a", 200), Pair("b", 400)] == ([Pair("a", 100), Pair("b", 200)]
|> pairs.map(, fn(_k, v) { v * 2 })
)
pop_until(
self: Pairs<key, value>,
until: fn(key, value) -> Bool,
) -> (Option<Pair<key, value>>, Pairs<key, value>)
Drop elements from an associative list until a predicate is satisfied.
Returns the first key/value pair that satisfies the predicate, and the rest
of the list after that key/value pair.
let predicate = fn(k, v) { k == "a" && v > 1 }
expect (None, []) = pairs.pop_until([], predicate)
expect (None, []) = pairs.pop_until([Pair("a", 1), Pair("b", 2)], predicate)
expect (Some(Pair("a", 3), []) = pairs.pop_until([Pair("a", 1), Pair("b", 2), Pair("a", 3)], predicate)
pop_until_and_then(
self: Pairs<key, value>,
until: fn(key, value) -> Bool,
return: fn(Option<Pair<key, value>>, Pairs<key, value>) -> result,
) -> result
Like pop_until but leverages backpassing.
let predicate = fn(k, v) { k == "a" && v > 1 }
expect None, [] <- pairs.pop_until_and_then([], predicate)
expect None, [] <- pairs.pop_until_and_then([Pair("a", 1), Pair("b", 2)], predicate)
expect Some(Pair("a", 3), [] <- pairs.pop_until_and_then([Pair("a", 1), Pair("b", 2), Pair("a", 3)], predicate)
Drop elements from an associative list until a given key is encountered.
Returns the first value at that key (if any), and the rest of the list after
that key/value pair.
expect (None, []) = pairs.pop_until_key([], "a")
expect (Some(1), [Pair("b", 2)]) = pairs.pop_until_key([Pair("a", 1), Pair("b", 2)], "a")
expect (Some(3), []) = pairs.pop_until_key([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "c")
expect (None, []) = pairs.pop_until_key([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "")
pop_until_key_and_then(
self: Pairs<key, value>,
until: key,
return: fn(Option<value>, Pairs<key, value>) -> result,
) -> result
A version of pop_until_key which leverages backpassing.
expect None, [] <- pairs.pop_until_key_and_then([], "a")
expect Some(1), [Pair("b", 2)] <- pairs.pop_until_key_and_then([Pair("a", 1), Pair("b", 2)], "a")
expect Some(3), [] <- pairs.pop_until_key_and_then([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "c")
expect None, [] <- pairs.pop_until_key_and_then([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "")
repsert_by_ascending_key(
self: Pairs<key, value>,
key: key,
value: value,
compare: fn(key, key) -> Ordering,
) -> Pairs<key, value>
Insert a value in the Pairs at a given key. If the key already exists,
its value is replaced.
The list is only traversed up to the given key and the traversal
stops as soon as a higher key is encountered. Said differently, the list
is assumed to be ordered by ascending keys! If it is not, expect the
unexpected.
use aiken/primitive/bytearray
[Pair("bar", 2), Pair("foo", 3)] == ([]
|> pairs.repsert_by_ascending_key(key: "foo", value: 1, compare: bytearray.compare)
|> pairs.repsert_by_ascending_key(key: "bar", value: 2, compare: bytearray.compare)
|> pairs.repsert_by_ascending_key(key: "foo", value: 3, compare: bytearray.compare)
)
Modifying Forcibly
More efficient version of delete_first, which fails if
thereβs no matching element to delete.
pairs.expect_delete_first([], "a") β π₯
pairs.expect_delete_first([Pair("a", 1)], "a") == []
pairs.expect_delete_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.expect_delete_first([Pair("a", 1), Pair("b", 2)], "c") β π₯
pairs.expect_delete_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)]
More efficient version of delete_last, which fails if
thereβs no matching element to delete.
pairs.expect_delete_last([], "a") β π₯
pairs.expect_delete_last([Pair("a", 1)], "a") == []
pairs.expect_delete_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.expect_delete_last([Pair("a", 1), Pair("b", 2)], "c") β π₯
pairs.expect_delete_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)]
expect_pop_until(
self: Pairs<key, value>,
until: fn(key, value) -> Bool,
) -> (Pair<key, value>, Pairs<key, value>)
More efficient version of pop_until, which fails if thereβs
no element matching the predicate.
let predicate = fn(k, v) { k == "a" && v > 1 }
π₯ = pairs.expect_pop_until([], predicate)
π₯ = pairs.expect_pop_until([Pair("a", 1), Pair("b", 2)], predicate)
expect (Pair("a", 3), []) = pairs.expect_pop_until([Pair("a", 1), Pair("b", 2), Pair("a", 3)], predicate)
expect_pop_until_and_then(
self: Pairs<key, value>,
until: fn(key, value) -> Bool,
return: fn(Pair<key, value>, Pairs<key, value>) -> result,
) -> result
A version of expect_pop_until which leverages backpassing.
let predicate = fn(k, v) { k == "a" && v > 1 }
π₯ <- pairs.expect_pop_until_and_then([], predicate)
π₯ <- pairs.expect_pop_until([Pair("a", 1), Pair("b", 2)], predicate)
expect Pair("a", 3), [] <- pairs.expect_pop_until_and_then([Pair("a", 1), Pair("b", 2), Pair("a", 3)], predicate)
More efficient version of pop_until_key which fails if the key isnβt found.
π₯ = pairs.expect_pop_until_key([], "a")
expect (1, [Pair("b", 2)]) = pairs.expect_pop_until_key([Pair("a", 1), Pair("b", 2)], "a")
expect (3, []) = pairs.expect_pop_until_key([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "c")
π₯ = pairs.expect_pop_until_key([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "")
expect_pop_until_key_and_then(
self: Pairs<key, value>,
until: key,
return: fn(value, Pairs<key, value>) -> result,
) -> result
A version of expect_pop_until_key which leverages backpassing.
π₯ <- pairs.expect_pop_until_key_and_then([], "a")
expect 1, [Pair("b", 2)] <- pairs.expect_pop_until_key_and_then([Pair("a", 1), Pair("b", 2)], "a")
expect 3, [] <- pairs.expect_pop_until_key_and_then([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "c")
π₯ <- pairs.expect_pop_until_key_and_then([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "")
Transforming
Fold over the key-value pairs in a pairs. The fold direction follows keys
in ascending order and is done from left-to-right.
1400 == ([Pair(1, 100), Pair(2, 200), Pair(3, 300)]
|> pairs.foldl(0, fn(k, v, result) { k * v + result })
)
use aiken/primitive/bytearray.{concat}
"a1b2c3" == ([Pair("a", "1"), Pair("b", "2"), Pair("c", "3")]
|> pairs.foldl("", fn(k, v, str) { concat(str, concat(k, v)) })
)
Fold over the key-value pairs in a Pairs. The fold direction follows the
order of elements in the Pairs and is done from right-to-left.
1400 == ([Pair(1, 100), Pair(2, 200), Pair(3, 300)]
|> pairs.foldr(0, fn(k, v, result) { k * v + result })
)
use aiken/primitive/bytearray.{concat}
"c3b2a1" == ([Pair("a", "1"), Pair("b", "2"), Pair("c", "3")]
|> pairs.foldr("", fn(k, v, str) { concat(str, concat(k, v)) })
)
Remove all key-value pairs matching the key from the Pairs. If the key is not found, no changes are made.
pairs.delete_all([], "a") == []
pairs.delete_all([Pair("a", 1)], "a") == []
pairs.delete_all([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.delete_all([Pair("a", 1), Pair("b", 2)], "c") == [Pair("a", 1), Pair("b", 2)]
pairs.delete_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2)]
Remove a single key-value pair from the Pairs. If the key is not found, no changes are made.
Duplicate keys are not deleted. Only the first key found is deleted.
pairs.delete_first([], "a") == []
pairs.delete_first([Pair("a", 1)], "a") == []
pairs.delete_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.delete_first([Pair("a", 1), Pair("b", 2)], "c") == [Pair("a", 1), Pair("b", 2)]
pairs.delete_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)]
Remove a single key-value pair from the Pairs. If the key is not found, no changes are made. Duplicate keys are not deleted. Only the last key found is deleted.
pairs.delete_last([], "a") == []
pairs.delete_last([Pair("a", 1)], "a") == []
pairs.delete_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.delete_last([Pair("a", 1), Pair("b", 2)], "c") == [Pair("a", 1), Pair("b", 2)]
pairs.delete_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)]
insert_by_ascending_key(
self: Pairs<key, value>,
key: key,
value: value,
compare: fn(key, key) -> Ordering,
) -> Pairs<key, value>
Insert a value in the Pairs at a given key. If the key already exists,
the value is added in front.
The list is only traversed up to the given key and the traversal stops as soon as a higher key is encountered. Said differently, the list is assumed to be ordered by ascending keys! If it is not, expect the unexpected.
use aiken/primitive/bytearray
[Pair("bar", 2), Pair("foo", 3), Pair("foo", 1)] == ([]
|> pairs.insert_by_ascending_key(key: "foo", value: 1, compare: bytearray.compare)
|> pairs.insert_by_ascending_key(key: "bar", value: 2, compare: bytearray.compare)
|> pairs.insert_by_ascending_key(key: "foo", value: 3, compare: bytearray.compare)
)
insert_with_by_ascending_key(
self: Pairs<key, value>,
key: key,
value: value,
compare: fn(key, key) -> Ordering,
with: fn(value, value) -> value,
) -> Pairs<key, value>
Like insert_by_ascending_key but specifies
how to combine two values on a key conflict.
The list is only traversed up to the given key and the traversal stops as soon as a higher key is encountered. Said differently, the list is assumed to be ordered by ascending keys! If it is not, expect the unexpected.
use aiken/primitive/bytearray
let add_integer = fn(x, y) { x + y }
[Pair("bar", 2), Pair("foo", 4)] == ([]
|> pairs.insert_with_by_ascending_key(key: "foo", value: 1, compare: bytearray.compare, with: add_integer)
|> pairs.insert_with_by_ascending_key(key: "bar", value: 2, compare: bytearray.compare, with: add_integer)
|> pairs.insert_with_by_ascending_key(key: "foo", value: 3, compare: bytearray.compare, with: add_integer)
)
Apply a function to all key-value pairs in a alist, replacing the values.
[Pair("a", 200), Pair("b", 400)] == ([Pair("a", 100), Pair("b", 200)]
|> pairs.map(, fn(_k, v) { v * 2 })
)
pop_until(
self: Pairs<key, value>,
until: fn(key, value) -> Bool,
) -> (Option<Pair<key, value>>, Pairs<key, value>)
Drop elements from an associative list until a predicate is satisfied. Returns the first key/value pair that satisfies the predicate, and the rest of the list after that key/value pair.
let predicate = fn(k, v) { k == "a" && v > 1 }
expect (None, []) = pairs.pop_until([], predicate)
expect (None, []) = pairs.pop_until([Pair("a", 1), Pair("b", 2)], predicate)
expect (Some(Pair("a", 3), []) = pairs.pop_until([Pair("a", 1), Pair("b", 2), Pair("a", 3)], predicate)
pop_until_and_then(
self: Pairs<key, value>,
until: fn(key, value) -> Bool,
return: fn(Option<Pair<key, value>>, Pairs<key, value>) -> result,
) -> result
Like pop_until but leverages backpassing.
let predicate = fn(k, v) { k == "a" && v > 1 }
expect None, [] <- pairs.pop_until_and_then([], predicate)
expect None, [] <- pairs.pop_until_and_then([Pair("a", 1), Pair("b", 2)], predicate)
expect Some(Pair("a", 3), [] <- pairs.pop_until_and_then([Pair("a", 1), Pair("b", 2), Pair("a", 3)], predicate)
Drop elements from an associative list until a given key is encountered. Returns the first value at that key (if any), and the rest of the list after that key/value pair.
expect (None, []) = pairs.pop_until_key([], "a")
expect (Some(1), [Pair("b", 2)]) = pairs.pop_until_key([Pair("a", 1), Pair("b", 2)], "a")
expect (Some(3), []) = pairs.pop_until_key([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "c")
expect (None, []) = pairs.pop_until_key([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "")
pop_until_key_and_then(
self: Pairs<key, value>,
until: key,
return: fn(Option<value>, Pairs<key, value>) -> result,
) -> result
A version of pop_until_key which leverages backpassing.
expect None, [] <- pairs.pop_until_key_and_then([], "a")
expect Some(1), [Pair("b", 2)] <- pairs.pop_until_key_and_then([Pair("a", 1), Pair("b", 2)], "a")
expect Some(3), [] <- pairs.pop_until_key_and_then([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "c")
expect None, [] <- pairs.pop_until_key_and_then([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "")
repsert_by_ascending_key(
self: Pairs<key, value>,
key: key,
value: value,
compare: fn(key, key) -> Ordering,
) -> Pairs<key, value>
Insert a value in the Pairs at a given key. If the key already exists,
its value is replaced.
The list is only traversed up to the given key and the traversal stops as soon as a higher key is encountered. Said differently, the list is assumed to be ordered by ascending keys! If it is not, expect the unexpected.
use aiken/primitive/bytearray
[Pair("bar", 2), Pair("foo", 3)] == ([]
|> pairs.repsert_by_ascending_key(key: "foo", value: 1, compare: bytearray.compare)
|> pairs.repsert_by_ascending_key(key: "bar", value: 2, compare: bytearray.compare)
|> pairs.repsert_by_ascending_key(key: "foo", value: 3, compare: bytearray.compare)
)
More efficient version of delete_first, which fails if
thereβs no matching element to delete.
pairs.expect_delete_first([], "a") β π₯
pairs.expect_delete_first([Pair("a", 1)], "a") == []
pairs.expect_delete_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.expect_delete_first([Pair("a", 1), Pair("b", 2)], "c") β π₯
pairs.expect_delete_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)]
More efficient version of delete_last, which fails if
thereβs no matching element to delete.
pairs.expect_delete_last([], "a") β π₯
pairs.expect_delete_last([Pair("a", 1)], "a") == []
pairs.expect_delete_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)]
pairs.expect_delete_last([Pair("a", 1), Pair("b", 2)], "c") β π₯
pairs.expect_delete_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)]
expect_pop_until(
self: Pairs<key, value>,
until: fn(key, value) -> Bool,
) -> (Pair<key, value>, Pairs<key, value>)
More efficient version of pop_until, which fails if thereβs
no element matching the predicate.
let predicate = fn(k, v) { k == "a" && v > 1 }
π₯ = pairs.expect_pop_until([], predicate)
π₯ = pairs.expect_pop_until([Pair("a", 1), Pair("b", 2)], predicate)
expect (Pair("a", 3), []) = pairs.expect_pop_until([Pair("a", 1), Pair("b", 2), Pair("a", 3)], predicate)
expect_pop_until_and_then(
self: Pairs<key, value>,
until: fn(key, value) -> Bool,
return: fn(Pair<key, value>, Pairs<key, value>) -> result,
) -> result
A version of expect_pop_until which leverages backpassing.
let predicate = fn(k, v) { k == "a" && v > 1 }
π₯ <- pairs.expect_pop_until_and_then([], predicate)
π₯ <- pairs.expect_pop_until([Pair("a", 1), Pair("b", 2)], predicate)
expect Pair("a", 3), [] <- pairs.expect_pop_until_and_then([Pair("a", 1), Pair("b", 2), Pair("a", 3)], predicate)
More efficient version of pop_until_key which fails if the key isnβt found.
π₯ = pairs.expect_pop_until_key([], "a")
expect (1, [Pair("b", 2)]) = pairs.expect_pop_until_key([Pair("a", 1), Pair("b", 2)], "a")
expect (3, []) = pairs.expect_pop_until_key([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "c")
π₯ = pairs.expect_pop_until_key([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "")
expect_pop_until_key_and_then(
self: Pairs<key, value>,
until: key,
return: fn(value, Pairs<key, value>) -> result,
) -> result
A version of expect_pop_until_key which leverages backpassing.
π₯ <- pairs.expect_pop_until_key_and_then([], "a")
expect 1, [Pair("b", 2)] <- pairs.expect_pop_until_key_and_then([Pair("a", 1), Pair("b", 2)], "a")
expect 3, [] <- pairs.expect_pop_until_key_and_then([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "c")
π₯ <- pairs.expect_pop_until_key_and_then([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "")
Transforming
Fold over the key-value pairs in a pairs. The fold direction follows keys
in ascending order and is done from left-to-right.
1400 == ([Pair(1, 100), Pair(2, 200), Pair(3, 300)]
|> pairs.foldl(0, fn(k, v, result) { k * v + result })
)
use aiken/primitive/bytearray.{concat}
"a1b2c3" == ([Pair("a", "1"), Pair("b", "2"), Pair("c", "3")]
|> pairs.foldl("", fn(k, v, str) { concat(str, concat(k, v)) })
)
Fold over the key-value pairs in a Pairs. The fold direction follows the
order of elements in the Pairs and is done from right-to-left.
1400 == ([Pair(1, 100), Pair(2, 200), Pair(3, 300)]
|> pairs.foldr(0, fn(k, v, result) { k * v + result })
)
use aiken/primitive/bytearray.{concat}
"c3b2a1" == ([Pair("a", "1"), Pair("b", "2"), Pair("c", "3")]
|> pairs.foldr("", fn(k, v, str) { concat(str, concat(k, v)) })
)
Fold over the key-value pairs in a pairs. The fold direction follows keys in ascending order and is done from left-to-right.
1400 == ([Pair(1, 100), Pair(2, 200), Pair(3, 300)]
|> pairs.foldl(0, fn(k, v, result) { k * v + result })
)
use aiken/primitive/bytearray.{concat}
"a1b2c3" == ([Pair("a", "1"), Pair("b", "2"), Pair("c", "3")]
|> pairs.foldl("", fn(k, v, str) { concat(str, concat(k, v)) })
)
Fold over the key-value pairs in a Pairs. The fold direction follows the order of elements in the Pairs and is done from right-to-left.
1400 == ([Pair(1, 100), Pair(2, 200), Pair(3, 300)]
|> pairs.foldr(0, fn(k, v, result) { k * v + result })
)
use aiken/primitive/bytearray.{concat}
"c3b2a1" == ([Pair("a", "1"), Pair("b", "2"), Pair("c", "3")]
|> pairs.foldr("", fn(k, v, str) { concat(str, concat(k, v)) })
)