Elixir v1.1.0 Dict behaviour
This module specifies the Dict API expected to be implemented by different dictionaries.
It also provides functions that redirect to the underlying Dict, allowing a developer to work with different Dict implementations using one API.
To create a new dict, use the new
functions defined
by each dict type:
HashDict.new #=> creates an empty HashDict
In the examples below, dict_impl
means a specific
Dict
implementation, for example HashDict
or Map
.
Warning
Do not use this module if you expect a certain Dict
implementation. For example, if you are working with
maps and you don’t need polymorphism, it is preferrable
to use the Map
module instead of the Dict
one.
Protocols
Besides implementing the functions in this module, all
dictionaries are required to implement the Access
protocol:
iex> dict = dict_impl.new
iex> dict = Dict.put(dict, :hello, :world)
iex> dict[:hello]
:world
As well as the Enumerable
and Collectable
protocols.
Match
Dictionaries are required to implement all operations
using the match (===
) operator.
Default implementation
Default implementations for some functions in the Dict
module
are provided via use Dict
.
For example:
defmodule MyDict do
use Dict
# implement required functions (see below)
# override default implementations if optimization
# is needed
end
The client module must contain the following functions:
All functions, except reduce/3
, are required by the Dict behaviour.
reduce/3
must be implemented as per the Enumerable protocol.
Based on these functions, Dict
generates default implementations
for the following functions:
drop/2
equal?/2
fetch!/2
get/2
get/3
get_lazy/3
get_and_update/3
has_key?/2
keys/1
merge/2
merge/3
pop/2
pop/3
pop_lazy/3
put_new/3
put_new_lazy/3
split/2
take/2
to_list/1
update/4
update!/3
values/1
All of these functions are defined as overridable, so you can provide your own implementation if needed.
Note you can also test your custom module via Dict
’s doctests:
defmodule MyDict do
# ...
end
defmodule MyTests do
use ExUnit.Case
doctest Dict
defp dict_impl, do: MyDict
end
Summary
Functions
Removes the entry stored under the given key
from dict
.
If dict
does not contain key
, returns the dictionary unchanged
Returns a new dict where the given keys
are removed from dict
.
All non-member keys are ignored
Checks if two dicts are equal using ===
Returns {:ok, value}
associated with key
in dict
.
If dict
does not contain key
, returns :error
Returns the value associated with key
in dict
. If dict
does not
contain key
, it raises KeyError
Returns the value associated with key
in dict
. If dict
does not
contain key
, returns default
(or nil
if not provided)
Gets a value from dict
and updates the value at key
in one pass
Returns the value associated with key
in dict
. If dict
does not
contain key
, it lazily evaluates fun
and returns its result
Returns whether the given key
exists in the given dict
Returns a list of all keys in dict
.
The keys are not guaranteed to be in any order
Merges the dict dict2
into dict dict1
Merges the dict dict2
into dict dict1
Returns the value associated with key
in dict
as
well as the dict
without key
Returns the value associated with key
in dict
as
well as the dict
without key
Stores the given value
under key
in dict
.
If dict
already has key
, the stored value is replaced by the new one
Puts the given value
under key
in dict
unless key
is already present
Evaluates fun
and puts the result under key
in dict
unless key
is already present
Returns the number of elements in dict
Returns a tuple of two dicts, where the first dict contains only
entries from dict
with keys in keys
, and the second dict
contains only entries from dict
with keys not in keys
Returns a new dict where only the keys in keys
from dict
are included
Returns a list of key-value pairs stored in dict
.
No particular order is enforced
Updates a value in dict
by calling fun
on the value to get a new value. If
key
is not present in dict
then initial
will be stored as the first
value
Updates a value in dict
by calling fun
on the value to get a new
value. An exception is generated if key
is not present in the dict
Returns a list of all values in dict
.
The values are not guaranteed to be in any order
Types
Functions
Removes the entry stored under the given key
from dict
.
If dict
does not contain key
, returns the dictionary unchanged.
Examples
iex> dict = Enum.into([a: 1, b: 2], dict_impl.new)
iex> dict = Dict.delete(dict, :a)
iex> Dict.get(dict, :a)
nil
iex> dict = Enum.into([b: 2], dict_impl.new)
iex> Dict.delete(dict, :a) == dict
true
Returns a new dict where the given keys
are removed from dict
.
All non-member keys are ignored.
Examples
iex> dict = Enum.into([a: 1, b: 2], dict_impl.new)
iex> dict = Dict.drop(dict, [:a, :c, :d])
iex> Dict.to_list(dict)
[b: 2]
iex> dict = Enum.into([a: 1, b: 2], dict_impl.new)
iex> dict = Dict.drop(dict, [:c, :d])
iex> Dict.to_list(dict) |> Enum.sort
[a: 1, b: 2]
Checks if two dicts are equal using ===
.
Notice this function is polymorphic as it compares dicts of any
type. Each dict implementation also provides an equal?
function,
but they can only compare dicts of the same type.
Examples
iex> dict1 = Enum.into([a: 2, b: 3, f: 5, c: 123], dict_impl.new)
iex> dict2 = [a: 2, b: 3, f: 5, c: 123]
iex> Dict.equal?(dict1, dict2)
true
iex> dict1 = Enum.into([a: 2, b: 3, f: 5, c: 123], dict_impl.new)
iex> dict2 = []
iex> Dict.equal?(dict1, dict2)
false
Returns {:ok, value}
associated with key
in dict
.
If dict
does not contain key
, returns :error
.
Examples
iex> dict = Enum.into([a: 1], dict_impl.new)
iex> Dict.fetch(dict, :a)
{:ok, 1}
iex> Dict.fetch(dict, :b)
:error
Returns the value associated with key
in dict
. If dict
does not
contain key
, it raises KeyError
.
Examples
iex> dict = Enum.into([a: 1], dict_impl.new)
iex> Dict.fetch!(dict, :a)
1
Returns the value associated with key
in dict
. If dict
does not
contain key
, returns default
(or nil
if not provided).
Examples
iex> dict = Enum.into([a: 1], dict_impl.new)
iex> Dict.get(dict, :a)
1
iex> Dict.get(dict, :b)
nil
iex> Dict.get(dict, :b, 3)
3
Gets a value from dict
and updates the value at key
in one pass.
This fun
argument receives the value of key
in dict
(or nil
if key
is not present) and must return a two-elements tuple: the “get” value (the
value retrieved from the dict which can be operated on before being returned)
and the new value to be stored under key
in dict
.
The returned value is a tuple with the “get” value returned by fun
and a new
dict with the updated value under key
.
Examples
iex> dict = Enum.into([a: 1], dict_impl.new)
iex> {get, new_dict} = Dict.get_and_update dict, :a, fn(current_value) ->
...> {current_value + 1, "foo"}
...> end
iex> get
2
iex> Dict.get(new_dict, :a)
"foo"
Returns the value associated with key
in dict
. If dict
does not
contain key
, it lazily evaluates fun
and returns its result.
This is useful if the default value is very expensive to calculate or generally difficult to set-up and tear-down again.
Examples
iex> dict = Enum.into([a: 1], dict_impl.new)
iex> fun = fn ->
...> # some expensive operation here
...> :result
...> end
iex> Dict.get_lazy(dict, :a, fun)
1
iex> Dict.get_lazy(dict, :b, fun)
:result
Returns whether the given key
exists in the given dict
.
Examples
iex> dict = Enum.into([a: 1], dict_impl.new)
iex> Dict.has_key?(dict, :a)
true
iex> Dict.has_key?(dict, :b)
false
Returns a list of all keys in dict
.
The keys are not guaranteed to be in any order.
Examples
iex> dict = Enum.into([a: 1, b: 2], dict_impl.new)
iex> Enum.sort(Dict.keys(dict))
[:a, :b]
Merges the dict dict2
into dict dict1
.
If one of the dict2
entries is found in dict1
, the
conflicting entries in dict2
have higher precedence.
Notice this function is polymorphic as it merges dicts of any
type. Each dict implementation also provides a merge
function,
but they can only merge dicts of the same type.
Examples
iex> dict1 = Enum.into([a: 1, b: 2], dict_impl.new)
iex> dict2 = Enum.into([a: 3, d: 4], dict_impl.new)
iex> dict = Dict.merge(dict1, dict2)
iex> [a: Dict.get(dict, :a), b: Dict.get(dict, :b), d: Dict.get(dict, :d)]
[a: 3, b: 2, d: 4]
Merges the dict dict2
into dict dict1
.
If one of the dict2
entries is found in dict1
, the function
will be invoked to resolve the conflict.
Notice this function is polymorphic as it merges dicts of any
type. Each dict implementation also provides a merge
function,
but they can only merge dicts of the same type.
Examples
iex> dict1 = Enum.into([a: 1, b: 2], dict_impl.new)
iex> dict2 = Enum.into([a: 3, d: 4], dict_impl.new)
iex> dict = Dict.merge(dict1, dict2, fn(_k, v1, v2) ->
...> v1 + v2
...> end)
iex> [a: Dict.get(dict, :a), b: Dict.get(dict, :b), d: Dict.get(dict, :d)]
[a: 4, b: 2, d: 4]
Returns the value associated with key
in dict
as
well as the dict
without key
.
If key
is not present in dict
, then the dict
will
be returned unmodified.
Examples
iex> dict = Enum.into([a: 1], dict_impl.new)
iex> {v, dict} = Dict.pop dict, :a
iex> {v, Enum.sort(dict)}
{1, []}
iex> dict = Enum.into([a: 1], dict_impl.new)
iex> {v, dict} = Dict.pop dict, :b
iex> {v, Enum.sort(dict)}
{nil, [a: 1]}
iex> dict = Enum.into([a: 1], dict_impl.new)
iex> {v, dict} = Dict.pop dict, :b, 3
iex> {v, Enum.sort(dict)}
{3, [a: 1]}
Returns the value associated with key
in dict
as
well as the dict
without key
.
If key
is not present in dict
, then the dict
will
be returned unmodified, and it will lazily evaluate fun
and return its result instead of the missing value.
This is useful if the default value is very expensive to calculate or generally difficult to set-up and tear-down again.
Examples
iex> dict = Enum.into([a: 1], dict_impl.new)
iex> fun = fn ->
...> # some expensive operation here
...> :result
...> end
iex> {v, dict} = Dict.pop_lazy dict, :a, fun
iex> {v, Enum.sort(dict)}
{1, []}
iex> dict = Enum.into([a: 1], dict_impl.new)
iex> fun = fn ->
...> # some expensive operation here
...> :result
...> end
iex> {v, dict} = Dict.pop_lazy dict, :b, fun
iex> {v, Enum.sort(dict)}
{:result, [a: 1]}
Stores the given value
under key
in dict
.
If dict
already has key
, the stored value is replaced by the new one.
Examples
iex> dict = Enum.into([a: 1, b: 2], dict_impl.new)
iex> dict = Dict.put(dict, :a, 3)
iex> Dict.get(dict, :a)
3
Puts the given value
under key
in dict
unless key
is already present.
Examples
iex> dict = Enum.into([a: 1, b: 2], dict_impl.new)
iex> dict = Dict.put_new(dict, :a, 3)
iex> Dict.get(dict, :a)
1
Evaluates fun
and puts the result under key
in dict
unless key
is already present.
This is useful if the value is very expensive to calculate or generally difficult to set-up and tear-down again.
Examples
iex> dict = Enum.into([a: 1, b: 2], dict_impl.new)
iex> fun = fn ->
...> # some expensive operation here
...> 3
...> end
iex> dict = Dict.put_new_lazy(dict, :a, fun)
iex> Dict.get(dict, :a)
1
iex> dict = Dict.put_new_lazy(dict, :c, fun)
iex> Dict.get(dict, :c)
3
Specs
size(t) :: non_neg_integer
Returns the number of elements in dict
.
Examples
iex> dict = Enum.into([a: 1, b: 2], dict_impl.new)
iex> Dict.size(dict)
2
Returns a tuple of two dicts, where the first dict contains only
entries from dict
with keys in keys
, and the second dict
contains only entries from dict
with keys not in keys
.
All non-member keys are ignored.
Examples
iex> dict = Enum.into([a: 1, b: 2, c: 3, d: 4], dict_impl.new)
iex> {dict1, dict2} = Dict.split(dict, [:a, :c, :e])
iex> {Dict.to_list(dict1) |> Enum.sort, Dict.to_list(dict2) |> Enum.sort}
{[a: 1, c: 3], [b: 2, d: 4]}
iex> dict = Enum.into([], dict_impl.new)
iex> {dict1, dict2} = Dict.split(dict, [:a, :c])
iex> {Dict.to_list(dict1), Dict.to_list(dict2)}
{[], []}
iex> dict = Enum.into([a: 1, b: 2], dict_impl.new)
iex> {dict1, dict2} = Dict.split(dict, [:a, :b, :c])
iex> {Dict.to_list(dict1) |> Enum.sort, Dict.to_list(dict2)}
{[a: 1, b: 2], []}
Returns a new dict where only the keys in keys
from dict
are included.
All non-member keys are ignored.
Examples
iex> dict = Enum.into([a: 1, b: 2], dict_impl.new)
iex> dict = Dict.take(dict, [:a, :c, :d])
iex> Dict.to_list(dict)
[a: 1]
iex> dict = Dict.take(dict, [:c, :d])
iex> Dict.to_list(dict)
[]
Specs
to_list(t) :: list
Returns a list of key-value pairs stored in dict
.
No particular order is enforced.
Examples
iex> dict = dict_impl.new
iex> dict = Dict.put(dict, :a, 1)
iex> Dict.to_list(dict)
[a: 1]
Updates a value in dict
by calling fun
on the value to get a new value. If
key
is not present in dict
then initial
will be stored as the first
value.
Examples
iex> dict = Enum.into([a: 1, b: 2], dict_impl.new)
iex> dict = Dict.update(dict, :c, 3, fn(val) -> -val end)
iex> Dict.get(dict, :c)
3
Updates a value in dict
by calling fun
on the value to get a new
value. An exception is generated if key
is not present in the dict.
Examples
iex> dict = Enum.into([a: 1, b: 2], dict_impl.new)
iex> dict = Dict.update!(dict, :a, fn(val) -> -val end)
iex> Dict.get(dict, :a)
-1