A.OrdMap (Aja v0.5.1) View Source

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> A.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.

A.OrdMap:

Examples

A.OrdMap offers the same API as Map :

iex> ord_map = A.OrdMap.new([b: "Bat", a: "Ant", c: "Cat"])
ord(%{b: "Bat", a: "Ant", c: "Cat"})
iex> A.OrdMap.get(ord_map, :c)
"Cat"
iex> A.OrdMap.fetch(ord_map, :a)
{:ok, "Ant"}
iex> A.OrdMap.put(ord_map, :d, "Dinosaur")
ord(%{b: "Bat", a: "Ant", c: "Cat", d: "Dinosaur"})
iex> A.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, A.OrdMap also offers some extra methods not present in Map, like:

  • first/1 and last/1 to efficiently retrieve the first / last key-value pair
  • foldl/3 and foldr/3 to efficiently fold (reduce) from left-to-right or right-to-left

Examples:

iex> ord_map = A.OrdMap.new(b: "Bat", a: "Ant", c: "Cat")
iex> A.OrdMap.first(ord_map)
{:b, "Bat"}
iex> A.OrdMap.last(ord_map)
{:c, "Cat"}
iex> A.OrdMap.foldr(ord_map, [], fn {_key, value}, acc -> [value <> "man" | acc] end)
["Batman", "Antman", "Catman"]

Access behaviour

A.OrdMap implements the Access behaviour.

iex> ord_map = A.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 A.OrdMap module can be used without any macro.

The A.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 A
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, A.ord/1 is able to generate the AST at compile time like the A.vec/1 macro.

The A.ord_size/1 macro can be used in guards:

iex> import A
iex> match?(v when ord_size(v) > 2, ord%{"一" => 1, "二" => 2, "三" => 3})
true

With Jason

iex> A.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 A.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 ^)
  • A.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 A.OrdMap.new/1 on a sparse ord map will rebuild a new dense one from scratch (which can be expensive).

iex> dense = A.OrdMap.new(a: "Ant", b: "Bat")
ord(%{a: "Ant", b: "Bat"})
iex> sparse = A.OrdMap.new(c: "Cat", a: "Ant", b: "Bat") |> A.OrdMap.delete(:c)
#A.OrdMap<%{a: "Ant", b: "Bat"}, sparse?: true>
iex> dense == sparse
false
iex> match?(^dense, sparse)
false
iex> A.OrdMap.equal?(dense, sparse)  # works with sparse maps, but less efficient
true
iex> new_dense = A.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 = A.OrdMap.new(c: "Cat", a: "Ant", b: "Bat") |> A.OrdMap.delete(:c)
#A.OrdMap<%{a: "Ant", b: "Bat"}, sparse?: true>
iex> A.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> A.OrdMap.new([one: 1, two: 2, three: 3]) |> A.OrdMap.delete(:three)
ord(%{one: 1, two: 2})

The dense?/1 and sparse?/1 functions can be used to check if a A.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 A.OrdMap is represented internally using the %A.OrdMap{} struct. This struct can be used whenever there's a need to pattern match on something being an A.OrdMap:

iex> match?(%A.OrdMap{}, A.OrdMap.new())
true

Note, however, than A.OrdMap is an opaque type: its struct internal fields must not be accessed directly.

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

A.OrdMap takes roughly 2~3x more memory than a regular map depending on the type of data:

iex> map_size = Map.new(1..100, fn i -> {i, i} end) |> :erts_debug.size()
358
iex> ord_map_size = A.OrdMap.new(1..100, fn i -> {i, i} end) |> :erts_debug.size()
1111
iex> ord_map_size / map_size
3.1033519553072626

Link to this section Summary

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.

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.

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.

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.

Link to this section Types

Specs

key() :: term()

Specs

t() :: t(key(), value())

Specs

t(key, value) :: internals(key, value)

Specs

value() :: term()

Link to this section Functions

Specs

delete(t(k, v), k) :: t(k, v) when k: key(), v: value()

Deletes the entry in ord_map for a specific key.

If the key does not exist, returns ord_map unchanged.

Examples

iex> ord_map = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.OrdMap.delete(ord_map, :b)
#A.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
iex> A.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 = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
ord(%{a: "Ant", b: "Bat", c: "Cat"})
iex> A.OrdMap.dense?(ord_map)
true
iex> sparse = A.OrdMap.delete(ord_map, :b)
#A.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
iex> A.OrdMap.dense?(sparse)
false

Specs

drop(t(k, v), [k]) :: t(k, v) when k: key(), v: value()

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 = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.OrdMap.drop(ord_map, [:b, :d])
#A.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
Link to this function

equal?(ord_map1, ord_map2)

View Source

Specs

equal?(t(), t()) :: boolean()

Checks if two ordered maps are equal, meaning they have the same key-value pairs in the same order.

Examples

iex> A.OrdMap.equal?(A.OrdMap.new(a: 1, b: 2), A.OrdMap.new(a: 1, b: 2))
true
iex> A.OrdMap.equal?(A.OrdMap.new(a: 1, b: 2), A.OrdMap.new(b: 2, a: 1))
false
iex> A.OrdMap.equal?(A.OrdMap.new(a: 1, b: 2), A.OrdMap.new(a: 3, b: 2))
false

Specs

fetch(t(k, v), k) :: {:ok, v} | :error when k: key(), v: value()

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 = A.OrdMap.new(a: "A", b: "B", c: "C")
iex> A.OrdMap.fetch(ord_map, :c)
{:ok, "C"}
iex> A.OrdMap.fetch(ord_map, :z)
:error

Specs

fetch!(t(k, v), k) :: v when k: key(), v: value()

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 = A.OrdMap.new(a: "A", b: "B", c: "C")
iex> A.OrdMap.fetch!(ord_map, :c)
"C"
iex> A.OrdMap.fetch!(ord_map, :z)
** (KeyError) key :z not found in: ord(%{a: "A", b: "B", c: "C"})
Link to this function

first(ord_map, default \\ nil)

View Source

Specs

first(t(k, v), default) :: {k, v} | default
when k: key(), v: value(), default: term()

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> A.OrdMap.new([b: "B", d: "D", a: "A", c: "C"]) |> A.OrdMap.first()
{:b, "B"}
iex> A.OrdMap.new([]) |> A.OrdMap.first()
nil
iex> A.OrdMap.new([]) |> A.OrdMap.first(:error)
:error
Link to this function

foldl(ord_map, acc, fun)

View Source

Folds (reduces) the given ord_map from the left with the function fun. Requires an accumulator acc.

Examples

iex> ord_map = A.OrdMap.new([b: "Bat", c: "Cat", a: "Ant"])
iex> A.OrdMap.foldl(ord_map, "", fn {_key, value}, acc -> value <> acc end)
"AntCatBat"
iex> A.OrdMap.foldl(ord_map, [], fn {key, value}, acc -> [{key, value <> "man"} | acc] end)
[a: "Antman", c: "Catman", b: "Batman"]
Link to this function

foldr(ord_map, acc, fun)

View Source

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 = A.OrdMap.new([b: "Bat", c: "Cat", a: "Ant"])
iex> A.OrdMap.foldr(ord_map, "", fn {_key, value}, acc -> value <> acc end)
"BatCatAnt"
iex> A.OrdMap.foldr(ord_map, [], fn {key, value}, acc -> [{key, value <> "man"} | acc] end)
[b: "Batman", c: "Catman", a: "Antman"]

Specs

from_struct(atom() | struct()) :: t()

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.

Example

defmodule User do
  defstruct [:name, :age]
end

A.OrdMap.from_struct(User)
ord(%{age: nil, name: nil})

A.OrdMap.from_struct(%User{name: "john", age: 44})
ord(%{age: 44, name: "john"})
Link to this function

get(ord_map, key, default \\ nil)

View Source

Specs

get(t(k, v), k, v) :: v | nil when k: key(), v: value()

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 = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.OrdMap.get(ord_map, :a)
"Ant"
iex> A.OrdMap.get(ord_map, :z)
nil
iex> A.OrdMap.get(ord_map, :z, "Zebra")
"Zebra"
Link to this function

get_and_update(ord_map, key, fun)

View Source

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> ord_map = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> {"bat", updated} = A.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} = A.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} = A.OrdMap.get_and_update(ord_map, :b, fn _ -> :pop end)
iex> updated
#A.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
iex> {nil, updated} = A.OrdMap.get_and_update(ord_map, :z, fn _ -> :pop end)
iex> updated
ord(%{a: "Ant", b: "Bat", c: "Cat"})
Link to this function

get_and_update!(ord_map, key, fun)

View Source

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> ord_map = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> {"bat", updated} = A.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> A.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"})
Link to this function

get_lazy(ord_map, key, fun)

View Source

Specs

get_lazy(t(k, v), k, v) :: v | nil when k: key(), v: value()

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 = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> expensive_fun = fn -> "Zebra" end
iex> A.OrdMap.get_lazy(ord_map, :a, expensive_fun)
"Ant"
iex> A.OrdMap.get_lazy(ord_map, :z, expensive_fun)
"Zebra"

Specs

has_key?(t(k, value()), k) :: boolean() when k: key()

Returns whether the given key exists in ord_map.

Examples

iex> ord_map = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.OrdMap.has_key?(ord_map, :a)
true
iex> A.OrdMap.has_key?(ord_map, :d)
false

Specs

keys(t(k, value())) :: [k] when k: key()

Returns all keys from ord_map.

Examples

iex> ord_map = A.OrdMap.new(b: "Bat", c: "Cat", a: "Ant")
iex> A.OrdMap.keys(ord_map)
[:b, :c, :a]
Link to this function

last(ord_map, default \\ nil)

View Source

Specs

last(t(k, v), default) :: {k, v} | default
when k: key(), v: value(), default: term()

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> A.OrdMap.new([b: "B", d: "D", a: "A", c: "C"]) |> A.OrdMap.last()
{:c, "C"}
iex> A.OrdMap.new([]) |> A.OrdMap.last()
nil
iex> A.OrdMap.new([]) |> A.OrdMap.last(:error)
:error
Link to this function

merge(ord_map, map_or_ord_map)

View Source

Specs

merge(t(k, v), t(k, v) | %{optional(k) => v}) :: t(k, v)
when k: key(), v: value()

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> A.OrdMap.merge(A.OrdMap.new(%{a: 1, b: 2}), A.OrdMap.new(%{a: 3, d: 4}))
ord(%{a: 3, b: 2, d: 4})
iex> A.OrdMap.merge(A.OrdMap.new(%{a: 1, b: 2}), %{a: 3, d: 4})
ord(%{a: 3, b: 2, d: 4})

Specs

new() :: t()

Returns a new empty ordered map.

Examples

iex> A.OrdMap.new()
ord(%{})

Specs

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> A.OrdMap.new(b: "Bat", a: "Ant", c: "Cat")
ord(%{b: "Bat", a: "Ant", c: "Cat"})
iex> A.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 = A.OrdMap.new(c: "Cat", a: "Ant", b: "Bat") |> A.OrdMap.delete(:c)
#A.OrdMap<%{a: "Ant", b: "Bat"}, sparse?: true>
iex> A.OrdMap.new(sparse)
ord(%{a: "Ant", b: "Bat"})

Specs

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> A.OrdMap.new([:a, :b], fn x -> {x, x} end)
ord(%{a: :a, b: :b})
Link to this function

pop(ord_map, key, default \\ nil)

View Source

Specs

pop(t(k, v), k, v) :: {v, t(k, v)} when k: key(), v: value()

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 = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> {"Bat", updated} = A.OrdMap.pop(ord_map, :b)
iex> updated
#A.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
iex> {nil, updated} = A.OrdMap.pop(ord_map, :z)
iex> updated
ord(%{a: "Ant", b: "Bat", c: "Cat"})
iex> {"Z", updated} = A.OrdMap.pop(ord_map, :z, "Z")
iex> updated
ord(%{a: "Ant", b: "Bat", c: "Cat"})

Specs

pop!(t(k, v), k) :: {v, t(k, v)} when k: key(), v: value()

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 = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> {"Bat", updated} = A.OrdMap.pop!(ord_map, :b)
iex> updated
#A.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
iex> A.OrdMap.pop!(ord_map, :z)
** (KeyError) key :z not found in: ord(%{a: "Ant", b: "Bat", c: "Cat"})
Link to this function

pop_lazy(ord_map, key, fun)

View Source

Specs

pop_lazy(t(k, v), k, (() -> v)) :: {v, t(k, v)} when k: key(), v: value()

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 = A.OrdMap.new(b: "Bat", a: "Ant", c: "Cat")
iex> expensive_fun = fn -> "Zebra" end
iex> {"Ant", updated} = A.OrdMap.pop_lazy(ord_map, :a, expensive_fun)
iex> updated
#A.OrdMap<%{b: "Bat", c: "Cat"}, sparse?: true>
iex> {"Zebra", not_updated} = A.OrdMap.pop_lazy(ord_map, :z, expensive_fun)
iex> not_updated
ord(%{b: "Bat", a: "Ant", c: "Cat"})
Link to this function

put(ord_map, key, value)

View Source

Specs

put(t(k, v), k, v) :: t(k, v) when k: key(), v: value()

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 = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.OrdMap.put(ord_map, :b, "Buffalo")
ord(%{a: "Ant", b: "Buffalo", c: "Cat"})
iex> A.OrdMap.put(ord_map, :d, "Dinosaur")
ord(%{a: "Ant", b: "Bat", c: "Cat", d: "Dinosaur"})
Link to this function

put_new(ord_map, key, value)

View Source

Specs

put_new(t(k, v), k, v) :: t(k, v) when k: key(), v: value()

Puts the given value under key unless the entry key already exists in ord_map.

Examples

iex> ord_map = A.OrdMap.new(b: "Bat", c: "Cat")
iex> A.OrdMap.put_new(ord_map, :a, "Ant")
ord(%{b: "Bat", c: "Cat", a: "Ant"})
iex> A.OrdMap.put_new(ord_map, :b, "Buffalo")
ord(%{b: "Bat", c: "Cat"})
Link to this function

put_new_lazy(ord_map, key, fun)

View Source

Specs

put_new_lazy(t(k, v), k, (() -> v)) :: t(k, v) when k: key(), v: value()

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 = A.OrdMap.new(b: "Bat", c: "Cat")
iex> expensive_fun = fn -> "Ant" end
iex> A.OrdMap.put_new_lazy(ord_map, :a, expensive_fun)
ord(%{b: "Bat", c: "Cat", a: "Ant"})
iex> A.OrdMap.put_new_lazy(ord_map, :b, expensive_fun)
ord(%{b: "Bat", c: "Cat"})
Link to this function

replace(ord_map, key, value)

View Source

Specs

replace(t(k, v), k, v) :: t(k, v) when k: key(), v: value()

Puts a value under key only if the key already exists in ord_map.

Examples

iex> ord_map = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.OrdMap.replace(ord_map, :b, "Buffalo")
ord(%{a: "Ant", b: "Buffalo", c: "Cat"})
iex> A.OrdMap.replace(ord_map, :d, "Dinosaur")
ord(%{a: "Ant", b: "Bat", c: "Cat"})
Link to this function

replace!(ord_map, key, value)

View Source

Specs

replace!(t(k, v), k, v) :: t(k, v) when k: key(), v: value()

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 = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.OrdMap.replace!(ord_map, :b, "Buffalo")
ord(%{a: "Ant", b: "Buffalo", c: "Cat"})
iex> A.OrdMap.replace!(ord_map, :d, "Dinosaur")
** (KeyError) key :d not found in: ord(%{a: "Ant", b: "Bat", c: "Cat"})

Specs

size(t()) :: non_neg_integer()

Returns the number of keys in ord_map.

Examples

iex> ord_map = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.OrdMap.size(ord_map)
3
iex> A.OrdMap.size(A.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 = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
ord(%{a: "Ant", b: "Bat", c: "Cat"})
iex> A.OrdMap.sparse?(ord_map)
false
iex> sparse = A.OrdMap.delete(ord_map, :b)
#A.OrdMap<%{a: "Ant", c: "Cat"}, sparse?: true>
iex> A.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 = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.OrdMap.take(ord_map, [:c, :e, :a])
ord(%{c: "Cat", a: "Ant"})

Specs

to_list(t(k, v)) :: [{k, v}] when k: key(), v: value()

Returns all key-values pairs from ord_map as a list.

Examples

iex> ord_map = A.OrdMap.new(b: "Bat", c: "Cat", a: "Ant")
iex> A.OrdMap.to_list(ord_map)
[b: "Bat", c: "Cat", a: "Ant"]
Link to this function

update(ord_map, key, default, fun)

View Source

Specs

update(t(k, v), k, v, (k -> v)) :: t(k, v) when k: key(), v: value()

Puts a value under key only if the key already exists in ord_map.

Examples

iex> ord_map = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.OrdMap.update(ord_map, :b, "N/A", &String.upcase/1)
ord(%{a: "Ant", b: "BAT", c: "Cat"})
iex> A.OrdMap.update(ord_map, :z, "N/A", &String.upcase/1)
ord(%{a: "Ant", b: "Bat", c: "Cat", z: "N/A"})
Link to this function

update!(ord_map, key, fun)

View Source

Specs

update!(t(k, v), k, v) :: t(k, v) when k: key(), v: value()

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 = A.OrdMap.new(a: "Ant", b: "Bat", c: "Cat")
iex> A.OrdMap.update!(ord_map, :b,  &String.upcase/1)
ord(%{a: "Ant", b: "BAT", c: "Cat"})
iex> A.OrdMap.update!(ord_map, :d, &String.upcase/1)
** (KeyError) key :d not found in: ord(%{a: "Ant", b: "Bat", c: "Cat"})

Specs

values(t(key(), v)) :: [v] when v: value()

Returns all values from ord_map.

Examples

iex> ord_map = A.OrdMap.new(b: "Bat", c: "Cat", a: "Ant")
iex> A.OrdMap.values(ord_map)
["Bat", "Cat", "Ant"]