View Source Aja.OrdMap (Aja v0.6.5)
A map preserving key insertion order, with efficient lookups, updates and enumeration.
It works like regular maps, except that the insertion order is preserved:
iex> %{"one" => 1, "two" => 2, "three" => 3}
%{"one" => 1, "three" => 3, "two" => 2}
iex> Aja.OrdMap.new([{"one", 1}, {"two", 2}, {"three", 3}])
ord(%{"one" => 1, "two" => 2, "three" => 3})
There is an unavoidable overhead compared to natively implemented maps, so keep using regular maps when you do not care about the insertion order.
- provides efficient (logarithmic) access: it is not a simple list of tuples
- implements the
Access
behaviour,Enum
/Inspect
/Collectable
protocols - optionally implements the
Jason.Encoder
protocol ifJason
is installed
Examples
Aja.OrdMap
offers the same API as Map
:
iex> ord_map = Aja.OrdMap.new([b: "Bat", a: "Ant", c: "Cat"])
ord(%{b: "Bat", a: "Ant", c: "Cat"})
iex> Aja.OrdMap.get(ord_map, :c)
"Cat"
iex> Aja.OrdMap.fetch(ord_map, :a)
{:ok, "Ant"}
iex> Aja.OrdMap.put(ord_map, :d, "Dinosaur")
ord(%{b: "Bat", a: "Ant", c: "Cat", d: "Dinosaur"})
iex> Aja.OrdMap.put(ord_map, :b, "Buffalo")
ord(%{b: "Buffalo", a: "Ant", c: "Cat"})
iex> Enum.to_list(ord_map)
[b: "Bat", a: "Ant", c: "Cat"]
iex> [d: "Dinosaur", b: "Buffalo", e: "Eel"] |> Enum.into(ord_map)
ord(%{b: "Buffalo", a: "Ant", c: "Cat", d: "Dinosaur", e: "Eel"})
Specific functions
Due to its ordered nature, Aja.OrdMap
also offers some extra methods not present in Map
, like:
first/1
andlast/1
to efficiently retrieve the first / last key-value pairfoldl/3
andfoldr/3
to efficiently fold (reduce) from left-to-right or right-to-left
Examples:
iex> ord_map = Aja.OrdMap.new(b: "Bat", a: "Ant", c: "Cat")
iex> Aja.OrdMap.first(ord_map)
{:b, "Bat"}
iex> Aja.OrdMap.last(ord_map)
{:c, "Cat"}
iex> Aja.OrdMap.foldr(ord_map, [], fn {_key, value}, acc -> [value <> "man" | acc] end)
["Batman", "Antman", "Catman"]
Access behaviour
Aja.OrdMap
implements the Access
behaviour.
iex> ord_map = Aja.OrdMap.new([a: "Ant", b: "Bat", c: "Cat"])
iex> ord_map[:a]
"Ant"
iex> put_in(ord_map[:b], "Buffalo")
ord(%{a: "Ant", b: "Buffalo", c: "Cat"})
iex> put_in(ord_map[:d], "Dinosaur")
ord(%{a: "Ant", b: "Bat", c: "Cat", d: "Dinosaur"})
iex> {"Cat", updated} = pop_in(ord_map[:c]); updated
ord(%{a: "Ant", b: "Bat"})
Convenience ord/1
and ord_size/1
macros
The Aja.OrdMap
module can be used without any macro.
The Aja.ord/1
macro does however provide some syntactic sugar to make
it more convenient to work with ordered maps, namely:
- construct new ordered maps without the clutter of a entry list
- pattern match on key-values like regular maps
- update some existing keys
Examples:
iex> import Aja
iex> ord_map = ord(%{"一" => 1, "二" => 2, "三" => 3})
ord(%{"一" => 1, "二" => 2, "三" => 3})
iex> ord(%{"三" => three, "一" => one}) = ord_map
iex> {one, three}
{1, 3}
iex> ord(%{ord_map | "二" => "NI!"})
ord(%{"一" => 1, "二" => "NI!", "三" => 3})
Notes:
- pattern-matching on keys is not affected by insertion order.
- For expressions with constant keys,
Aja.ord/1
is able to generate the AST at compile time like theAja.vec/1
macro.
The Aja.ord_size/1
macro can be used in guards:
iex> import Aja
iex> match?(v when ord_size(v) > 2, ord%{"一" => 1, "二" => 2, "三" => 3})
true
With Jason
iex> Aja.OrdMap.new([{"un", 1}, {"deux", 2}, {"trois", 3}]) |> Jason.encode!()
"{\"un\":1,\"deux\":2,\"trois\":3}"
JSON encoding preserves the insertion order. Comparing with a regular map:
iex> Map.new([{"un", 1}, {"deux", 2}, {"trois", 3}]) |> Jason.encode!()
"{\"deux\":2,\"trois\":3,\"un\":1}"
There is no way as of now to decode JSON using Aja.OrdMap
.
Key deletion and sparse maps
Due to the underlying structures being used, efficient key deletion implies keeping around some "holes" to avoid rebuilding the whole structure.
Such an ord map will be called sparse, while an ord map that never had a key deleted will be referred as dense.
The implications of sparse structures are multiple:
- unlike dense structures, they cannot be compared as erlang terms
(using either
==/2
,===/2
or the pin operator^
) Aja.OrdMap.equal?/2
can safely compare both sparse and dense structures, but is slower for sparse- enumerating sparse structures is less efficient than dense ones
Calling Aja.OrdMap.new/1
on a sparse ord map will rebuild a new dense one from scratch (which can be expensive).
iex> dense = Aja.OrdMap.new(a: "Ant", b: "Bat")
ord(%{a: "Ant", b: "Bat"})
iex> sparse = Aja.OrdMap.new(c: "Cat", a: "Ant", b: "Bat") |> Aja.OrdMap.delete(:c)
#Aja.OrdMap<%{a: "Ant", b: "Bat"}, sparse?: true>
iex> dense == sparse
false
iex> match?(^dense, sparse)
false
iex> Aja.OrdMap.equal?(dense, sparse) # works with sparse maps, but less efficient
true
iex> new_dense = Aja.OrdMap.new(sparse) # rebuild a dense map from a sparse one
ord(%{a: "Ant", b: "Bat"})
iex> new_dense === dense
true
In order to avoid having to worry about memory issues when adding and deleting keys successively, ord maps cannot be more than half sparse, and are periodically rebuilt as dense upon deletion.
iex> sparse = Aja.OrdMap.new(c: "Cat", a: "Ant", b: "Bat") |> Aja.OrdMap.delete(:c)
#Aja.OrdMap<%{a: "Ant", b: "Bat"}, sparse?: true>
iex> Aja.OrdMap.delete(sparse, :a)
ord(%{b: "Bat"})
Note: Deleting the last key does not make a dense ord map sparse. This is not a bug, but an expected behavior due to how data is stored.
iex> Aja.OrdMap.new([one: 1, two: 2, three: 3]) |> Aja.OrdMap.delete(:three)
ord(%{one: 1, two: 2})
The dense?/1
and sparse?/1
functions can be used to check if a Aja.OrdMap
is dense or sparse.
While this design puts some burden on the developer, the idea behind it is:
- to keep it as convenient and performant as possible unless deletion is necessary
- to be transparent about sparse structures and their limitation
- instead of constantly rebuild new dense structures, let users decide the best timing to do it
- still work fine with sparse structures, but in a degraded mode
- protect users about potential memory leaks and performance issues
Pattern-matching and opaque type
An Aja.OrdMap
is represented internally using the %Aja.OrdMap{}
struct. This struct
can be used whenever there's a need to pattern match on something being an Aja.OrdMap
:
iex> match?(%Aja.OrdMap{}, Aja.OrdMap.new())
true
Note, however, that Aja.OrdMap
should be considered an opaque type: its struct internal fields
must not be accessed directly (even if not enforced by dialyzer because of pattern-matching).
As discussed in the previous section, ord/1
and ord_size/1
makes it
possible to pattern match on keys as well as check the type and size.
Memory overhead
Aja.OrdMap
takes roughly 2~3x more memory than a regular map depending on the type of data.
:erts_debug.size(map)
can be used to confirm the overhead on a concrete use case.
Summary
Types
The type of an Aja.OrdMap
with keys of the type key
and values of the type value
.
Functions
Deletes the entry in ord_map
for a specific key
.
Returns true
if ord_map
is dense; otherwise returns false
.
Drops the given keys
from ord_map
.
Checks if two ordered maps are equal, meaning they have the same key-value pairs in the same order.
Fetches the value for a specific key
and returns it in a ok-entry.
If the key does not exist, returns :error.
Fetches the value for a specific key
in the given ord_map
,
erroring out if ord_map
doesn't contain key
.
Returns a new ordered map containing only those pairs from ord_map
for which fun
returns a truthy value.
Finds the fist {key, value}
pair in ord_map
.
Folds (reduces) the given ord_map
from the left with the function fun
.
Requires an accumulator acc
.
Folds (reduces) the given ord_map
from the right with the function fun
.
Requires an accumulator acc
.
Builds an ordered map from the given keys
list and the fixed value
.
Converts a struct
to an ordered map.
Gets the value for a specific key
in ord_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 ord_map
.
Returns whether the given key
exists in ord_map
.
Returns all keys from ord_map
.
Finds the last {key, value}
pair in ord_map
.
Merges a map or an ordered map into an ord_map
.
Returns a new empty ordered map.
Creates an ordered map from an enumerable
.
Creates an ordered map from an enumerable
via the given transform
function.
Returns the value for key
and the updated ordered map without key
.
Returns the value for key
and the updated ordered map without key
.
Lazily returns and removes the value associated with key
in ord_map
.
Puts the given value
under key
in ord_map
.
Puts the given value
under key
unless the entry key
already exists in ord_map
.
Evaluates fun
and puts the result under key
in ord_map
unless key
is already present.
Returns a new ordered map excluding the pairs from ord_map
for which fun
returns a truthy value.
Preserves the order of ord_map
.
Puts a value under key
only if the key
already exists in ord_map
.
Puts a value under key
only if the key
already exists in ord_map
.
Returns the number of keys in ord_map
.
Returns true
if ord_map
is sparse; otherwise returns false
.
Returns a new ordered map with all the key-value pairs in ord_map
where the key
is in keys
.
Returns all key-values pairs from ord_map
as a list.
Puts a value under key
only if the key
already exists in ord_map
.
Puts a value under key
only if the key
already exists in ord_map
.
Returns all values from ord_map
.
Types
@type key() :: term()
@type t(key, value) :: internals(key, value)
The type of an Aja.OrdMap
with keys of the type key
and values of the type value
.
It should be considered opaque even though it isn't enforced by dialyzer to enable pattern-matching.
@type value() :: term()
Functions
Deletes the entry in ord_map
for a specific key
.
If the key
does not exist, returns ord_map
unchanged.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> Aja.OrdMap.delete(ord_map, :b)
#Aja.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
iex> Aja.OrdMap.delete(ord_map, :z)
ord(%{a: "Ant", b: "Bat", c: "Cat"})
Returns true
if ord_map
is dense; otherwise returns false
.
See the section about sparse structures for more information.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
ord(%{a: "Ant", b: "Bat", c: "Cat"})
iex> Aja.OrdMap.dense?(ord_map)
true
iex> sparse = Aja.OrdMap.delete(ord_map, :b)
#Aja.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
iex> Aja.OrdMap.dense?(sparse)
false
Drops the given keys
from ord_map
.
If keys
contains keys that are not in ord_map
, they're simply ignored.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> Aja.OrdMap.drop(ord_map, [:b, :d])
#Aja.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
Checks if two ordered maps are equal, meaning they have the same key-value pairs in the same order.
Examples
iex> Aja.OrdMap.equal?(Aja.OrdMap.new(a: 1, b: 2), Aja.OrdMap.new(a: 1, b: 2))
true
iex> Aja.OrdMap.equal?(Aja.OrdMap.new(a: 1, b: 2), Aja.OrdMap.new(b: 2, a: 1))
false
iex> Aja.OrdMap.equal?(Aja.OrdMap.new(a: 1, b: 2), Aja.OrdMap.new(a: 3, b: 2))
false
Fetches the value for a specific key
and returns it in a ok-entry.
If the key does not exist, returns :error.
Examples
iex> ord_map = Aja.OrdMap.new(a: "A", b: "B", c: "C")
iex> Aja.OrdMap.fetch(ord_map, :c)
{:ok, "C"}
iex> Aja.OrdMap.fetch(ord_map, :z)
:error
Fetches the value for a specific key
in the given ord_map
,
erroring out if ord_map
doesn't contain key
.
If ord_map
doesn't contain key
, a KeyError
exception is raised.
Examples
iex> ord_map = Aja.OrdMap.new(a: "A", b: "B", c: "C")
iex> Aja.OrdMap.fetch!(ord_map, :c)
"C"
iex> Aja.OrdMap.fetch!(ord_map, :z)
** (KeyError) key :z not found in: ord(%{a: "A", b: "B", c: "C"})
Returns a new ordered map containing only those pairs from ord_map
for which fun
returns a truthy value.
fun
receives the key and value of each of the elements in ord_map
as a key-value pair.
Preserves the order of ord_map
.
Mirrors Map.filter/2
.
See also reject/2
which discards all elements where the function returns a truthy value.
Examples
iex> ord_map = Aja.OrdMap.new([three: 3, two: 2, one: 1, zero: 0])
iex> Aja.OrdMap.filter(ord_map, fn {_key, val} -> rem(val, 2) == 1 end)
ord(%{three: 3, one: 1})
Finds the fist {key, value}
pair in ord_map
.
Returns a {key, value}
entry if ord_map
is non-empty, or nil
else.
Examples
iex> Aja.OrdMap.new([b: "B", d: "D", a: "A", c: "C"]) |> Aja.OrdMap.first()
{:b, "B"}
iex> Aja.OrdMap.new([]) |> Aja.OrdMap.first()
nil
iex> Aja.OrdMap.new([]) |> Aja.OrdMap.first(:error)
:error
Folds (reduces) the given ord_map
from the left with the function fun
.
Requires an accumulator acc
.
Examples
iex> ord_map = Aja.OrdMap.new([b: "Bat", c: "Cat", a: "Ant"])
iex> Aja.OrdMap.foldl(ord_map, "", fn {_key, value}, acc -> value <> acc end)
"AntCatBat"
iex> Aja.OrdMap.foldl(ord_map, [], fn {key, value}, acc -> [{key, value <> "man"} | acc] end)
[a: "Antman", c: "Catman", b: "Batman"]
Folds (reduces) the given ord_map
from the right with the function fun
.
Requires an accumulator acc
.
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> ord_map = Aja.OrdMap.new([b: "Bat", c: "Cat", a: "Ant"])
iex> Aja.OrdMap.foldr(ord_map, "", fn {_key, value}, acc -> value <> acc end)
"BatCatAnt"
iex> Aja.OrdMap.foldr(ord_map, [], fn {key, value}, acc -> [{key, value <> "man"} | acc] end)
[b: "Batman", c: "Catman", a: "Antman"]
Builds an ordered map from the given keys
list and the fixed value
.
Preserves the order of keys
.
Examples
iex> Aja.OrdMap.from_keys([:c, :a, :d, :b], 0)
ord(%{c: 0, a: 0, d: 0, b: 0})
Converts a struct
to an ordered map.
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.
Respects the field order in Elixir >= 1.14.
Example
defmodule User do
defstruct [:name, :age]
end
Aja.OrdMap.from_struct(User)
ord(%{name: nil, age: nil})
Aja.OrdMap.from_struct(%User{name: "john", age: 44})
ord(%{name: "john", age: 44})
Gets the value for a specific key
in ord_map
.
If key
is present in ord_map
then its value value
is
returned. Otherwise, default
is returned.
If default
is not provided, nil
is used.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> Aja.OrdMap.get(ord_map, :a)
"Ant"
iex> Aja.OrdMap.get(ord_map, :z)
nil
iex> Aja.OrdMap.get(ord_map, :z, "Zebra")
"Zebra"
@spec 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> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> {"bat", updated} = Aja.OrdMap.get_and_update(ord_map, :b, fn current_value ->
...> {current_value && String.downcase(current_value), "Buffalo"}
...> end)
iex> updated
ord(%{a: "Ant", b: "Buffalo", c: "Cat"})
iex> {nil, updated} = Aja.OrdMap.get_and_update(ord_map, :z, fn current_value ->
...> {current_value && String.downcase(current_value), "Zebra"}
...> end)
iex> updated
ord(%{a: "Ant", b: "Bat", c: "Cat", z: "Zebra"})
iex> {"Bat", updated} = Aja.OrdMap.get_and_update(ord_map, :b, fn _ -> :pop end)
iex> updated
#Aja.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
iex> {nil, updated} = Aja.OrdMap.get_and_update(ord_map, :z, fn _ -> :pop end)
iex> updated
ord(%{a: "Ant", b: "Bat", c: "Cat"})
@spec 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> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> {"bat", updated} = Aja.OrdMap.get_and_update!(ord_map, :b, fn current_value ->
...> {current_value && String.downcase(current_value), "Buffalo"}
...> end)
iex> updated
ord(%{a: "Ant", b: "Buffalo", c: "Cat"})
iex> Aja.OrdMap.get_and_update!(ord_map, :z, fn current_value ->
...> {current_value && String.downcase(current_value), "Zebra"}
...> end)
** (KeyError) key :z not found in: ord(%{a: "Ant", b: "Bat", c: "Cat"})
Gets the value for a specific key
in ord_map
.
If key
is present in ord_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> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> expensive_fun = fn -> "Zebra" end
iex> Aja.OrdMap.get_lazy(ord_map, :a, expensive_fun)
"Ant"
iex> Aja.OrdMap.get_lazy(ord_map, :z, expensive_fun)
"Zebra"
Returns whether the given key
exists in ord_map
.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> Aja.OrdMap.has_key?(ord_map, :a)
true
iex> Aja.OrdMap.has_key?(ord_map, :d)
false
Returns all keys from ord_map
.
Examples
iex> ord_map = Aja.OrdMap.new(b: "Bat", c: "Cat", a: "Ant")
iex> Aja.OrdMap.keys(ord_map)
[:b, :c, :a]
Finds the last {key, value}
pair in ord_map
.
Returns a {key, value}
entry if ord_map
is non-empty, or nil
else.
Can be accessed efficiently due to the underlying vector.
Examples
iex> Aja.OrdMap.new([b: "B", d: "D", a: "A", c: "C"]) |> Aja.OrdMap.last()
{:c, "C"}
iex> Aja.OrdMap.new([]) |> Aja.OrdMap.last()
nil
iex> Aja.OrdMap.new([]) |> Aja.OrdMap.last(:error)
:error
Merges a map or an ordered map into an ord_map
.
All keys in map_or_ord_map
will be added to ord_map
, overriding any existing one
(i.e., the keys in map_or_ord_map
"have precedence" over the ones in ord_map
).
Examples
iex> Aja.OrdMap.merge(Aja.OrdMap.new(%{a: 1, b: 2}), Aja.OrdMap.new(%{a: 3, d: 4}))
ord(%{a: 3, b: 2, d: 4})
iex> Aja.OrdMap.merge(Aja.OrdMap.new(%{a: 1, b: 2}), %{a: 3, d: 4})
ord(%{a: 3, b: 2, d: 4})
@spec new() :: t()
Returns a new empty ordered map.
Examples
iex> Aja.OrdMap.new()
ord(%{})
@spec new(Enumerable.t()) :: t(key(), value())
Creates an ordered map from an enumerable
.
Preserves the original order of keys. Duplicated keys are removed; the latest one prevails.
Examples
iex> Aja.OrdMap.new(b: "Bat", a: "Ant", c: "Cat")
ord(%{b: "Bat", a: "Ant", c: "Cat"})
iex> Aja.OrdMap.new(b: "Bat", a: "Ant", b: "Buffalo", a: "Antelope")
ord(%{b: "Buffalo", a: "Antelope"})
new/1
will return dense ord maps untouched, but will rebuild sparse ord maps from scratch.
This can be used to build a dense ord map from from a sparse one.
See the section about sparse structures for more information.
iex> sparse = Aja.OrdMap.new(c: "Cat", a: "Ant", b: "Bat") |> Aja.OrdMap.delete(:c)
#Aja.OrdMap<%{a: "Ant", b: "Bat"}, sparse?: true>
iex> Aja.OrdMap.new(sparse)
ord(%{a: "Ant", b: "Bat"})
@spec new(Enumerable.t(), (term() -> {k, v})) :: t(k, v) when k: key(), v: value()
Creates an ordered map from an enumerable
via the given transform
function.
Preserves the original order of keys. Duplicated keys are removed; the latest one prevails.
Examples
iex> Aja.OrdMap.new([:a, :b], fn x -> {x, x} end)
ord(%{a: :a, b: :b})
Returns the value for key
and the updated ordered map without key
.
If key
is present in the ordered map with a value value
,
{value, new_ord_map}
is returned.
If key
is not present in the ordered map, {default, ord_map}
is returned.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> {"Bat", updated} = Aja.OrdMap.pop(ord_map, :b)
iex> updated
#Aja.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
iex> {nil, updated} = Aja.OrdMap.pop(ord_map, :z)
iex> updated
ord(%{a: "Ant", b: "Bat", c: "Cat"})
iex> {"Z", updated} = Aja.OrdMap.pop(ord_map, :z, "Z")
iex> updated
ord(%{a: "Ant", b: "Bat", c: "Cat"})
Returns the value for key
and the updated ordered map without key
.
Behaves the same as pop/3
but raises if key
is not present in ord_map
.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> {"Bat", updated} = Aja.OrdMap.pop!(ord_map, :b)
iex> updated
#Aja.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
iex> Aja.OrdMap.pop!(ord_map, :z)
** (KeyError) key :z not found in: ord(%{a: "Ant", b: "Bat", c: "Cat"})
Lazily returns and removes the value associated with key
in ord_map
.
If key
is present in ord_map
, it returns {value, new_map}
where value
is the value of
the key and new_map
is the result of removing key
from ord_map
. If key
is not present in ord_map
, {fun_result, ord_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> ord_map = Aja.OrdMap.new(b: "Bat", a: "Ant", c: "Cat")
iex> expensive_fun = fn -> "Zebra" end
iex> {"Ant", updated} = Aja.OrdMap.pop_lazy(ord_map, :a, expensive_fun)
iex> updated
#Aja.OrdMap<%{b: "Bat", c: "Cat"}, sparse?: true>
iex> {"Zebra", not_updated} = Aja.OrdMap.pop_lazy(ord_map, :z, expensive_fun)
iex> not_updated
ord(%{b: "Bat", a: "Ant", c: "Cat"})
Puts the given value
under key
in ord_map
.
If the key
does exist, it overwrites the existing value without
changing its current location.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> Aja.OrdMap.put(ord_map, :b, "Buffalo")
ord(%{a: "Ant", b: "Buffalo", c: "Cat"})
iex> Aja.OrdMap.put(ord_map, :d, "Dinosaur")
ord(%{a: "Ant", b: "Bat", c: "Cat", d: "Dinosaur"})
Puts the given value
under key
unless the entry key
already exists in ord_map
.
Examples
iex> ord_map = Aja.OrdMap.new(b: "Bat", c: "Cat")
iex> Aja.OrdMap.put_new(ord_map, :a, "Ant")
ord(%{b: "Bat", c: "Cat", a: "Ant"})
iex> Aja.OrdMap.put_new(ord_map, :b, "Buffalo")
ord(%{b: "Bat", c: "Cat"})
Evaluates fun
and puts the result under key
in ord_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> ord_map = Aja.OrdMap.new(b: "Bat", c: "Cat")
iex> expensive_fun = fn -> "Ant" end
iex> Aja.OrdMap.put_new_lazy(ord_map, :a, expensive_fun)
ord(%{b: "Bat", c: "Cat", a: "Ant"})
iex> Aja.OrdMap.put_new_lazy(ord_map, :b, expensive_fun)
ord(%{b: "Bat", c: "Cat"})
Returns a new ordered map excluding the pairs from ord_map
for which fun
returns a truthy value.
Preserves the order of ord_map
.
Mirrors Map.reject/2
.
See also filter/2
.
Examples
iex> ord_map = Aja.OrdMap.new([zero: 0, one: 1, two: 2, three: 3])
iex> Aja.OrdMap.reject(ord_map, fn {_key, val} -> rem(val, 2) == 1 end)
ord(%{zero: 0, two: 2})
Puts a value under key
only if the key
already exists in ord_map
.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> Aja.OrdMap.replace(ord_map, :b, "Buffalo")
ord(%{a: "Ant", b: "Buffalo", c: "Cat"})
iex> Aja.OrdMap.replace(ord_map, :d, "Dinosaur")
ord(%{a: "Ant", b: "Bat", c: "Cat"})
Puts a value under key
only if the key
already exists in ord_map
.
If key
is not present in ord_map
, a KeyError
exception is raised.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> Aja.OrdMap.replace!(ord_map, :b, "Buffalo")
ord(%{a: "Ant", b: "Buffalo", c: "Cat"})
iex> Aja.OrdMap.replace!(ord_map, :d, "Dinosaur")
** (KeyError) key :d not found in: ord(%{a: "Ant", b: "Bat", c: "Cat"})
@spec size(t()) :: non_neg_integer()
Returns the number of keys in ord_map
.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> Aja.OrdMap.size(ord_map)
3
iex> Aja.OrdMap.size(Aja.OrdMap.new())
0
Returns true
if ord_map
is sparse; otherwise returns false
.
See the section about sparse structures for more information.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
ord(%{a: "Ant", b: "Bat", c: "Cat"})
iex> Aja.OrdMap.sparse?(ord_map)
false
iex> sparse = Aja.OrdMap.delete(ord_map, :b)
#Aja.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
iex> Aja.OrdMap.sparse?(sparse)
true
Returns a new ordered map with all the key-value pairs in ord_map
where the key
is in keys
.
If keys
contains keys that are not in ord_map
, they're simply ignored.
Respects the order of the keys
list.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> Aja.OrdMap.take(ord_map, [:c, :e, :a])
ord(%{c: "Cat", a: "Ant"})
Returns all key-values pairs from ord_map
as a list.
Examples
iex> ord_map = Aja.OrdMap.new(b: "Bat", c: "Cat", a: "Ant")
iex> Aja.OrdMap.to_list(ord_map)
[b: "Bat", c: "Cat", a: "Ant"]
Puts a value under key
only if the key
already exists in ord_map
.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> Aja.OrdMap.update(ord_map, :b, "N/A", &String.upcase/1)
ord(%{a: "Ant", b: "BAT", c: "Cat"})
iex> Aja.OrdMap.update(ord_map, :z, "N/A", &String.upcase/1)
ord(%{a: "Ant", b: "Bat", c: "Cat", z: "N/A"})
Puts a value under key
only if the key
already exists in ord_map
.
If key
is not present in ord_map
, a KeyError
exception is raised.
Examples
iex> ord_map = Aja.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> Aja.OrdMap.update!(ord_map, :b, &String.upcase/1)
ord(%{a: "Ant", b: "BAT", c: "Cat"})
iex> Aja.OrdMap.update!(ord_map, :d, &String.upcase/1)
** (KeyError) key :d not found in: ord(%{a: "Ant", b: "Bat", c: "Cat"})
Returns all values from ord_map
.
Examples
iex> ord_map = Aja.OrdMap.new(b: "Bat", c: "Cat", a: "Ant")
iex> Aja.OrdMap.values(ord_map)
["Bat", "Cat", "Ant"]