A.RBMap (Aja v0.2.0) View Source
A Red-Black tree implementation of a map. It keeps keys sorted in ascending order.
Erlang's :gb_trees
offer a similar functionality.
However A.RBMap
:
- is faster
- is easier to use: pipe-friendliness,
Access
behaviour,Enum
/Inspect
/Collectable
protocols - rebalances the tree on deletion unlike
:gb_trees
- optionally implements the
Jason.Encoder
protocol ifJason
is installed
Examples
A.RBMap
offers the same API as Map
:
iex> rb_map = A.RBMap.new([b: "Bat", a: "Ant", c: "Cat"])
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
iex> A.RBMap.get(rb_map, :c)
"Cat"
iex> A.RBMap.put(rb_map, :d, "Dinosaur")
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat", d: "Dinosaur"}>
iex> A.RBMap.delete(rb_map, :b)
#A.RBMap<%{a: "Ant", c: "Cat"}>
iex> Enum.to_list(rb_map)
[a: "Ant", b: "Bat", c: "Cat"]
iex> [c: "Cat", b: "Buffalo"] |> Enum.into(A.RBMap.new([a: "Ant", b: "Bat", d: "Dinosaur"]))
#A.RBMap<%{a: "Ant", b: "Buffalo", c: "Cat", d: "Dinosaur"}>
Tree-specific functions
Due to its sorted nature, A.RBMap
also offers some extra methods not present in Map
, like:
first/1
andlast/1
to efficiently retrieve the first (smallest) / last (largest) key-value pairpop_first/1
andpop_last/1
to efficiently pop the first (smallest) / last (largest) key-value pairfoldl/3
andfoldr/3
to efficiently fold (reduce) from left-to-right or right-to-left
Examples:
iex> rb_map = A.RBMap.new(%{1 => "一", 2 => "二", 3 => "三"})
iex> A.RBMap.first(rb_map)
{1, "一"}
iex> {3, "三", updated} = A.RBMap.pop_last(rb_map)
iex> updated
#A.RBMap<%{1 => "一", 2 => "二"}>
iex> A.RBMap.foldr(rb_map, [], fn {_key, value}, acc -> [value | acc] end)
["一", "二", "三"]
Access behaviour
A.RBMap
implements the Access
behaviour.
iex> rb_map = A.RBMap.new([b: "Bat", a: "Ant", c: "Cat"])
iex> rb_map[:a]
"Ant"
iex> put_in(rb_map[:b], "Buffalo")
#A.RBMap<%{a: "Ant", b: "Buffalo", c: "Cat"}>
iex> put_in(rb_map[:d], "Dinosaur")
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat", d: "Dinosaur"}>
iex> {"Cat", updated} = pop_in(rb_map[:c])
iex> updated
#A.RBMap<%{a: "Ant", b: "Bat"}>
With Jason
iex> A.RBMap.new(%{1 => "一", 2 => "二", 11 => "十一"}) |> Jason.encode!()
"{\"1\":\"一\",\"2\":\"二\",\"11\":\"十一\"}"
It also preserves the key order.
Limitations: pattern-matching and equality
Like :gb_trees
, A.RBMap
s face two strong limitations:
- pattern-matching on key-values like maps is NOT POSSIBLE
- comparisons based on
==/2
,===/2
or the pin operator^
are UNRELIABLE
In Elixir, pattern-matching and equality for structs work based on their internal representation. While this is a pragmatic design choice that simplifies the language, it means that we cannot rededine how they work for custom data structures.
Tree-based maps that are semantically equal (same key-value pairs in the same order) might be considered non-equal when comparing their internals, because there is not a unique way of representing one same map.
A.RBMap.equal?/2
should be used instead:
iex> rb_map1 = A.RBMap.new([a: "Ant", b: "Bat"])
#A.RBMap<%{a: "Ant", b: "Bat"}>
iex> rb_map2 = A.RBMap.new([b: "Bat", a: "Ant"])
#A.RBMap<%{a: "Ant", b: "Bat"}>
iex> rb_map1 == rb_map2
false
iex> A.RBMap.equal?(rb_map1, rb_map2)
true
iex> match?(^rb_map1, rb_map2)
false
An A.RBMap
is represented internally using the %A.RBMap{}
struct. This struct
can be used whenever there's a need to pattern match on something being an A.RBMap
:
iex> match?(%A.RBMap{}, A.RBMap.new(a: "Ant"))
true
Note, however, than A.RBMap
is an opaque type:
its struct internal fields must not be accessed directly.
Note about numbers
Unlike regular maps, A.RBMap
s only uses ordering for key comparisons,
not strict comparisons. Integers and floats are indistiguinshable as keys.
iex> %{1 => "一", 2 => "二"} |> Map.fetch(2.0)
:error
iex> A.RBMap.new(%{1 => "一", 2 => "二"}) |> A.RBMap.fetch(2.0)
{:ok, "二"}
Erlang's :gb_trees
module works the same.
Difference with A.OrdMap
A.OrdMap
keeps track of key insertion orderA.RBMap
keeps keys sorted in ascending order whatever the insertion order is
Underlying Red-Black Tree implementation
The underlying red-black tree implementation is available in A.RBTree
and is used
in other modules such as A.RBSet
, A.OrdMap
as well.
The algorithm detail is described in its documentation.
Link to this section Summary
Functions
Deletes the entry in rb_map
for a specific key
.
Drops the given keys
from rb_map
.
Checks if two maps are equal.
Fetches the value for a specific key
and returns it in a ok-tuple.
If the key does not exist, returns :error.
Fetches the value for a specific key
and returns it in a ok-tuple.
If the key does not exist, returns :error.
Finds the {key, value}
pair corresponding to the smallest key
in rb_map
.
Returns nil
for empty maps.
Folds (reduces) the given map from the right with a function. Requires an accumulator.
Folds (reduces) the given map from the right with a function. Requires an accumulator.
Converts a struct
to a A.RBMap
.
Gets the value for a specific key
in rb_map
.
Gets the value from key
and updates it, all in one pass.
Gets the value from key
and updates it, all in one pass.
Gets the value for a specific key
in rb_map
.
Returns whether the given key
exists in rb_map
.
Returns all keys from rb_map
.
Finds the {key, value}
pair corresponding to the largest key
in rb_map
.
Returns nil
for empty maps.
Merges two maps into one.
Returns a new empty map.
Creates a map from an enumerable
.
Creates a map from an enumerable
via the given transform
function.
Returns the value for key
and the updated map without key
.
Returns the value for key
and the updated map without key
.
Finds and pops the {key, value}
pair corresponding to the smallest key
in rb_map
.
Finds and pops the {key, value}
pair corresponding to the largest key
in rb_map
.
Lazily returns and removes the value associated with key
in rb_map
.
Puts the given value
under key
in rb_map
.
Puts the given value
under key
unless the entry key
already exists in rb_map
.
Evaluates fun
and puts the result under key
in rb_map
unless key
is already present.
Puts a value under key
only if the key
already exists in rb_map
.
Puts a value under key
only if the key
already exists in rb_map
.
Returns the number of keys in rb_map
.
Returns a new map with all the key-value pairs in rb_map
where the key
is in keys
.
Returns all values from rb_map
.
Updates the key
in rb_map
with the given function.
Puts a value under key
only if the key
already exists in rb_map
.
Returns all values from rb_map
.
Link to this section Types
Link to this section Functions
Specs
Deletes the entry in rb_map
for a specific key
.
If the key
does not exist, returns rb_map
unchanged.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.RBMap.delete(rb_map, :b)
#A.RBMap<%{a: "Ant", c: "Cat"}>
iex> A.RBMap.delete(rb_map, :z)
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
Specs
Drops the given keys
from rb_map
.
If keys
contains keys that are not in rb_map
, they're simply ignored.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.RBMap.drop(rb_map, [:b, :d])
#A.RBMap<%{a: "Ant", c: "Cat"}>
Specs
Checks if two maps are equal.
The comparison between keys is done using ==/2
, the comparison between values with strict equality ===/2
.
Examples
iex> A.RBMap.equal?(A.RBMap.new(a: 1, b: 2), A.RBMap.new(b: 2, a: 1))
true
iex> A.RBMap.equal?(A.RBMap.new([{1, "一"}, {2, "二"}]), A.RBMap.new([{1, "一"}, {2, "二"}]))
true
iex> A.RBMap.equal?(A.RBMap.new(a: 1, b: 2), A.RBMap.new(a: 3, b: 2))
false
iex> A.RBMap.equal?(A.RBMap.new(a: 1, b: 2), A.RBMap.new(a: 1.0, b: 2.0))
false
Specs
Fetches the value for a specific key
and returns it in a ok-tuple.
If the key does not exist, returns :error.
Examples
iex> rb_map = A.RBMap.new(a: "A", b: "B", c: "C")
iex> A.RBMap.fetch(rb_map, :c)
{:ok, "C"}
iex> A.RBMap.fetch(rb_map, :z)
:error
Specs
Fetches the value for a specific key
and returns it in a ok-tuple.
If the key does not exist, returns :error.
Examples
iex> rb_map = A.RBMap.new(a: "A", b: "B", c: "C")
iex> A.RBMap.fetch!(rb_map, :c)
"C"
iex> A.RBMap.fetch!(rb_map, :z)
** (KeyError) key :z not found in: #A.RBMap<%{a: "A", b: "B", c: "C"}>
Specs
Finds the {key, value}
pair corresponding to the smallest key
in rb_map
.
Returns nil
for empty maps.
This is very efficient and can be done in O(log(n)).
It should be preferred over Enum.min/3
.
Examples
iex> A.RBMap.new([b: "B", d: "D", a: "A", c: "C"]) |> A.RBMap.first()
{:a, "A"}
iex> A.RBMap.new([]) |> A.RBMap.first()
nil
Folds (reduces) the given map from the right with a function. Requires an accumulator.
Examples
iex> rb_map = A.RBMap.new([b: 22, a: 11, c: 33])
iex> A.RBMap.foldl(rb_map, 0, fn {_key, value}, acc -> value + acc end)
66
iex> A.RBMap.foldl(rb_map, [], fn {key, value}, acc -> [{key, value * 2} | acc] end)
[c: 66, b: 44, a: 22]
Folds (reduces) the given map from the right with a function. Requires an accumulator.
Unlike linked lists, this is as efficient as foldl/3
. This can typically save a call
to Enum.reverse/1
on the result when building a list.
Examples
iex> rb_map = A.RBMap.new([b: 22, a: 11, c: 33])
iex> A.RBMap.foldr(rb_map, 0, fn {_key, value}, acc -> value + acc end)
66
iex> A.RBMap.foldr(rb_map, [], fn {key, value}, acc -> [{key, value * 2} | acc] end)
[a: 22, b: 44, c: 66]
Specs
Converts a struct
to a A.RBMap
.
It accepts the struct module or a struct itself and
simply removes the __struct__
field from the given struct
or from a new struct generated from the given module.
Example
defmodule User do
defstruct [:name, :age]
end
A.RBMap.from_struct(User)
#A.RBMap<%{age: nil, name: nil}>
A.RBMap.from_struct(%User{name: "john", age: 44})
#A.RBMap<%{name: "john"}>
Specs
Gets the value for a specific key
in rb_map
.
If key
is present in rb_map
then its value value
is
returned. Otherwise, default
is returned.
If default
is not provided, nil
is used.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.RBMap.get(rb_map, :a)
"Ant"
iex> A.RBMap.get(rb_map, :z)
nil
iex> A.RBMap.get(rb_map, :z, "Zebra")
"Zebra"
Specs
get_and_update(t(k, v), k, (v -> {returned, v} | :pop)) :: {returned, t(k, v)} when k: key(), v: value(), returned: term()
Gets the value from key
and updates it, all in one pass.
Mirrors Map.get_and_update/3
, see its documentation.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> {"bat", updated} = A.RBMap.get_and_update(rb_map, :b, fn current_value ->
...> {current_value && String.downcase(current_value), "Buffalo"}
...> end)
iex> updated
#A.RBMap<%{a: "Ant", b: "Buffalo", c: "Cat"}>
iex> {nil, updated} = A.RBMap.get_and_update(rb_map, :z, fn current_value ->
...> {current_value && String.downcase(current_value), "Zebra"}
...> end)
iex> updated
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat", z: "Zebra"}>
iex> {"Bat", updated} = A.RBMap.get_and_update(rb_map, :b, fn _ -> :pop end)
iex> updated
#A.RBMap<%{a: "Ant", c: "Cat"}>
iex> {nil, updated} = A.RBMap.get_and_update(rb_map, :z, fn _ -> :pop end)
iex> updated
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
Specs
get_and_update!(t(k, v), k, (v -> {returned, v} | :pop)) :: {returned, t(k, v)} when k: key(), v: value(), returned: term()
Gets the value from key
and updates it, all in one pass.
Mirrors Map.get_and_update!/3
, see its documentation.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> {"bat", updated} = A.RBMap.get_and_update!(rb_map, :b, fn current_value ->
...> {current_value && String.downcase(current_value), "Buffalo"}
...> end)
iex> updated
#A.RBMap<%{a: "Ant", b: "Buffalo", c: "Cat"}>
iex> A.RBMap.get_and_update!(rb_map, :z, fn current_value ->
...> {current_value && String.downcase(current_value), "Zebra"}
...> end)
** (KeyError) key :z not found in: #A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
Specs
Gets the value for a specific key
in rb_map
.
If key
is present in rb_map
then its value value
is
returned. Otherwise, fun
is evaluated and its result is returned.
This is useful if the default value is very expensive to calculate or generally difficult to setup and teardown again.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> expensive_fun = fn -> "Zebra" end
iex> A.RBMap.get_lazy(rb_map, :a, expensive_fun)
"Ant"
iex> A.RBMap.get_lazy(rb_map, :z, expensive_fun)
"Zebra"
Specs
Returns whether the given key
exists in rb_map
.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.RBMap.has_key?(rb_map, :a)
true
iex> A.RBMap.has_key?(rb_map, :d)
false
iex> A.RBMap.has_key?(A.RBMap.new(%{1.0 => "uno"}), 1)
true
Specs
iterator(t(k, v)) :: A.RBTree.iterator({k, v}) when k: key(), v: value()
Specs
Returns all keys from rb_map
.
Examples
iex> rb_map = A.RBMap.new(b: "Bat", c: "Cat", a: "Ant")
iex> A.RBMap.keys(rb_map)
[:a, :b, :c]
Specs
Finds the {key, value}
pair corresponding to the largest key
in rb_map
.
Returns nil
for empty maps.
This is very efficient and can be done in O(log(n)).
It should be preferred over Enum.max/3
.
Examples
iex> A.RBMap.new([b: "B", d: "D", a: "A", c: "C"]) |> A.RBMap.last()
{:d, "D"}
iex> A.RBMap.new([]) |> A.RBMap.last()
nil
Specs
Merges two maps into one.
All keys in rb_map2
will be added to rb_map1
, overriding any existing one
(i.e., the keys in rb_map2
"have precedence" over the ones in rb_map1
).
Examples
iex> A.RBMap.merge(A.RBMap.new(%{a: 1, b: 2}), A.RBMap.new(%{a: 3, d: 4}))
#A.RBMap<%{a: 3, b: 2, d: 4}>
Specs
new() :: t()
Returns a new empty map.
Examples
iex> A.RBMap.new()
#A.RBMap<%{}>
Specs
new(Enumerable.t()) :: t()
Creates a map from an enumerable
.
Keys are sorted upon insertion, and duplicated keys are removed; the latest one prevails.
Examples
iex> A.RBMap.new(b: "Bat", a: "Ant", c: "Cat")
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
iex> A.RBMap.new(b: "Bat", a: "Ant", b: "Buffalo", a: "Antelope")
#A.RBMap<%{a: "Antelope", b: "Buffalo"}>
Specs
new(Enumerable.t(), (term() -> {k, v})) :: t(k, v) when k: key(), v: value()
Creates a map from an enumerable
via the given transform
function.
Duplicated keys are removed; the latest one prevails.
Examples
iex> A.RBMap.new([:a, :b], fn x -> {x, x} end)
#A.RBMap<%{a: :a, b: :b}>
Specs
See A.RBTree.next/1
.
Specs
Returns the value for key
and the updated map without key
.
If key
is present in the map with a value value
,
{value, new_rb_map}
is returned.
If key
is not present in the map, {default, rb_map}
is returned.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> {"Bat", updated} = A.RBMap.pop(rb_map, :b)
iex> updated
#A.RBMap<%{a: "Ant", c: "Cat"}>
iex> {nil, updated} = A.RBMap.pop(rb_map, :z)
iex> updated
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
iex> {"Z", updated} = A.RBMap.pop(rb_map, :z, "Z")
iex> updated
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
Specs
Returns the value for key
and the updated map without key
.
Behaves the same as pop/3
but raises if key
is not present in rb_map
.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> {"Bat", updated} = A.RBMap.pop!(rb_map, :b)
iex> updated
#A.RBMap<%{a: "Ant", c: "Cat"}>
iex> A.RBMap.pop!(rb_map, :z)
** (KeyError) key :z not found in: #A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
Specs
Finds and pops the {key, value}
pair corresponding to the smallest key
in rb_map
.
Returns a {key, value, new_tree}
tuple for non-empty maps, nil
for empty maps
Examples
iex> rb_map = A.RBMap.new([b: "B", d: "D", a: "A", c: "C"])
#A.RBMap<%{a: "A", b: "B", c: "C", d: "D"}>
iex> {:a, "A", updated} = A.RBMap.pop_first(rb_map)
iex> updated
#A.RBMap<%{b: "B", c: "C", d: "D"}>
iex> A.RBMap.new() |> A.RBMap.pop_first()
nil
Specs
Finds and pops the {key, value}
pair corresponding to the largest key
in rb_map
.
Returns a {key, value, new_tree}
tuple for non-empty maps, nil
for empty maps
Examples
iex> rb_map = A.RBMap.new([b: "B", d: "D", a: "A", c: "C"])
#A.RBMap<%{a: "A", b: "B", c: "C", d: "D"}>
iex> {:d, "D", updated} = A.RBMap.pop_last(rb_map)
iex> updated
#A.RBMap<%{a: "A", b: "B", c: "C"}>
iex> A.RBMap.new() |> A.RBMap.pop_last()
nil
Specs
Lazily returns and removes the value associated with key
in rb_map
.
If key
is present in rb_map
, it returns {value, new_map}
where value
is the value of
the key and new_map
is the result of removing key
from rb_map
. If key
is not present in rb_map
, {fun_result, rB_map}
is returned, where fun_result
is the result of applying fun
.
This is useful if the default value is very expensive to calculate or generally difficult to setup and teardown again.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> expensive_fun = fn -> "Zebra" end
iex> {"Ant", updated} = A.RBMap.pop_lazy(rb_map, :a, expensive_fun)
iex> updated
#A.RBMap<%{b: "Bat", c: "Cat"}>
iex> {"Zebra", not_updated} = A.RBMap.pop_lazy(rb_map, :z, expensive_fun)
iex> not_updated
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
Specs
Puts the given value
under key
in rb_map
.
If the key
does exist, it overwrites the existing value.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.RBMap.put(rb_map, :b, "Buffalo")
#A.RBMap<%{a: "Ant", b: "Buffalo", c: "Cat"}>
iex> A.RBMap.put(rb_map, :d, "Dinosaur")
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat", d: "Dinosaur"}>
Specs
Puts the given value
under key
unless the entry key
already exists in rb_map
.
Examples
iex> rb_map = A.RBMap.new(b: "Bat", c: "Cat")
iex> A.RBMap.put_new(rb_map, :a, "Ant")
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
iex> A.RBMap.put_new(rb_map, :b, "Buffalo")
#A.RBMap<%{b: "Bat", c: "Cat"}>
Specs
Evaluates fun
and puts the result under key
in rb_map
unless key
is already present.
This function is useful in case you want to compute the value to put under
key
only if key
is not already present, as for example, when the value is expensive to
calculate or generally difficult to setup and teardown again.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", c: "Cat")
iex> expensive_fun = fn -> "Buffalo" end
iex> A.RBMap.put_new_lazy(rb_map, :b, expensive_fun)
#A.RBMap<%{a: "Ant", b: "Buffalo", c: "Cat"}>
iex> A.RBMap.put_new_lazy(rb_map, :a, expensive_fun)
#A.RBMap<%{a: "Ant", c: "Cat"}>
Specs
Puts a value under key
only if the key
already exists in rb_map
.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.RBMap.replace(rb_map, :b, "Buffalo")
#A.RBMap<%{a: "Ant", b: "Buffalo", c: "Cat"}>
iex> A.RBMap.replace(rb_map, :d, "Dinosaur")
#A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
Specs
Puts a value under key
only if the key
already exists in rb_map
.
If key
is not present in rb_map
, a KeyError
exception is raised.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.RBMap.replace!(rb_map, :b, "Buffalo")
#A.RBMap<%{a: "Ant", b: "Buffalo", c: "Cat"}>
iex> A.RBMap.replace!(rb_map, :d, "Dinosaur")
** (KeyError) key :d not found in: #A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
Specs
size(t()) :: non_neg_integer()
Returns the number of keys in rb_map
.
Examples
iex> A.RBMap.size(A.RBMap.new(a: 1, b: 2, c: 3))
3
iex> A.RBMap.size(A.RBMap.new(a: 1, a: 2, a: 3))
1
Returns a new map with all the key-value pairs in rb_map
where the key
is in keys
.
If keys
contains keys that are not in rb_map
, they're simply ignored.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.RBMap.take(rb_map, [:c, :e, :a])
#A.RBMap<%{a: "Ant", c: "Cat"}>
Specs
Returns all values from rb_map
.
Examples
iex> rb_map = A.RBMap.new(b: "Bat", c: "Cat", a: "Ant")
iex> A.RBMap.to_list(rb_map)
[a: "Ant", b: "Bat", c: "Cat"]
Specs
Updates the key
in rb_map
with the given function.
If key
is present in rb_map
then the existing value is passed to fun
and its result is
used as the updated value of key
. If key
is
not present in rb_map
, default
is inserted as the value of key
. The default
value will not be passed through the update function.
Examples
iex> rb_map = A.RBMap.new(b: "Bat", c: "Cat")
iex>A.RBMap.update(rb_map, :b, "N/A", &String.upcase/1)
#A.RBMap<%{b: "BAT", c: "Cat"}>
iex>A.RBMap.update(rb_map, :a, "N/A", &String.upcase/1)
#A.RBMap<%{a: "N/A", b: "Bat", c: "Cat"}>
Specs
Puts a value under key
only if the key
already exists in rb_map
.
If key
is not present in rb_map
, a KeyError
exception is raised.
Examples
iex> rb_map = A.RBMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.RBMap.update!(rb_map, :b, &String.upcase/1)
#A.RBMap<%{a: "Ant", b: "BAT", c: "Cat"}>
iex> A.RBMap.update!(rb_map, :d, &String.upcase/1)
** (KeyError) key :d not found in: #A.RBMap<%{a: "Ant", b: "Bat", c: "Cat"}>
Specs
Returns all values from rb_map
.
Examples
iex> rb_map = A.RBMap.new(b: "Bat", c: "Cat", a: "Ant")
iex> A.RBMap.values(rb_map)
["Ant", "Bat", "Cat"]