DualMap (dual_map_ex v0.1.2)

A DualMap is simply a dual-entry map struct that allows you to reference pairs of data using both, a key or a value. In a DualMap you can look up a value from its key or a key from its value.

In simple terms we could say that a DualMap is a map where there is no difference between key and value, both can be either one or the other.

How does it work?

A DualMap actually stores 2 maps, a direct one with the key => value pairs, and a reverse one with the value => key pairs. At the same time it also stores metadata about the names (ids) of the datas (called master keys).

To create a new DualMap you must use the DualMap.new function. You must pass to it a pair of names that will be the identifiers of the master keys.

DualMap.new({:hostname, :ip})

The order of the master keys is important. If you later want to make insertions into the DualMap and you use the DualMap.put_ordered function the value pairs will assume that they are ordered as defined at the time of creating the DualMap with DualMap.new.

Let's see some examples:

iex> dm = DualMap.new({:hostname, :ip})
[]
iex> DualMap.put_ordered(dm, [
  {"ns3", "192.168.0.4"},
  {"ns2", "192.168.0.3"},
  {"ns1", "192.168.0.2"}
])
[
  {"ns1", "192.168.0.2"},
  {"ns2", "192.168.0.3"},
  {"ns3", "192.168.0.4"}
]
iex> DualMap.delete(dm, :ip, "192.168.0.3")
[
  {"ns1", "192.168.0.2"},
  {"ns3", "192.168.0.4"}
]

Summary

Types

t()

DualMap struct

Functions

Return de size of the DualMap counting the number of pairs.

Delete a pair of datas and returns the DualMap without that pair. The pair is found looking for key in the the internal map indexed by master_key.

Just the same as delete/3 but you can pass a list of keys to delete.

Checks if two DualMaps are equal.

Just as get/4 but do not accept default parameter. If the key exists, will return the tuple {:ok, value} and if not :error.

Work equals to fetch/3 but erroring out if key doesn't exists.

Returns the value asociated to key taking the internal map indexed by master_key. If key does not exists in the map, default or nil is returned.

Return the complete internal map indexed by master_key.

Checks if key exists within DualMap.

Return a list with all the keys of the internal map indexed by master_key.

Checks if the pair key_value (tuple size 2) exists within DualMap either as key => value or as value => key.

Returns an empty DualMap struct. The order of the master keys are important for posterior operations with the struct.

Returns a DualMap struct initialized with the values indicated in the second argument. As the new/1 function, the order of the master keys are important for posterior operations with the struct.

Insert or replace one or more pairs of datas in a DualMap. If the third parameters is a list of tuples, every one is inserted/replaced in the DualMap secuentialy. With this function you need pass the a master_key to indicate which value of the tuple will be interpreted as key and which one as value.

This function is similar to put/3 but you does not need pass a master key because the function will assume that you are sending the keys and values in the same order as you defined when you created the DualMap with new/1 or new/2.

Return a list of the pairs {key, value} taking the map indexed by the first master_key defined with new/1 or new/2. This function is used by inspect to print the DualMap.

Return a list with all the values of the internal map indexed by master_key.

Types

t()

@type t() :: %DualMap{
  __data: term(),
  __master_keys_map: term(),
  __ordered_master_keys: term()
}

DualMap struct

Functions

count(dual_map)

@spec count(t()) :: pos_integer()

Return de size of the DualMap counting the number of pairs.

delete(dual_map, master_key1, key1)

@spec delete(t(), master_key :: any(), key :: any()) :: t()

Delete a pair of datas and returns the DualMap without that pair. The pair is found looking for key in the the internal map indexed by master_key.

Examples

iex> dm = DualMap.new({:hostname, :ip}, [
  {"ns3", "192.168.0.4"},
  {"ns2", "192.168.0.3"},
  {"ns1", "192.168.0.2"}
])
[
  {"ns1", "192.168.0.2"},
  {"ns2", "192.168.0.3"},
  {"ns3", "192.168.0.4"}
]
iex> DualMap.delete(dm, :ip, "192.168.0.3")
[
  {"ns1", "192.168.0.2"},
  {"ns3", "192.168.0.4"}
]

drop(dual_map, master_key1, list)

@spec drop(t(), master_key :: any(), list()) :: t()

Just the same as delete/3 but you can pass a list of keys to delete.

Examples

iex> dm = DualMap.new({:hostname, :ip}, [
  {"ns3", "192.168.0.4"},
  {"ns2", "192.168.0.3"},
  {"ns1", "192.168.0.2"}
])
[
  {"ns1", "192.168.0.2"},
  {"ns2", "192.168.0.3"},
  {"ns3", "192.168.0.4"}
]
iex> DualMap.drop(dm, :ip, ["192.168.0.3", "192.168.0.2"])
[{"ns3", "192.168.0.4"}]

equal?(dual_map1, dual_map2)

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

Checks if two DualMaps are equal.

Two maps are considered to be equal if both internal maps contains the same keys and values.

fetch(dual_map, master_key, key)

@spec fetch(t(), any(), any()) :: {:ok, any()} | :error

Just as get/4 but do not accept default parameter. If the key exists, will return the tuple {:ok, value} and if not :error.

Examples

iex> dm = DualMap.new({:hostname, :ip}, [
  {"ns3", "192.168.0.4"},
  {"ns2", "192.168.0.3"},
  {"ns1", "192.168.0.2"}
])
iex> DualMap.fetch(dm, :ip, "192.168.0.4")
{:ok, "ns3"}
iex> DualMap.fetch(dm, :ip, "192.168.0.6")
:error

fetch!(dual_map, master_key, key)

@spec fetch!(t(), any(), any()) :: any()

Work equals to fetch/3 but erroring out if key doesn't exists.

get(dual_map, master_key, key, default \\ nil)

@spec get(t(), master_key :: any(), key :: any(), default :: any()) :: any()

Returns the value asociated to key taking the internal map indexed by master_key. If key does not exists in the map, default or nil is returned.

Examples

iex> dm = DualMap.new({:hostname, :ip}, [
  {"ns3", "192.168.0.4"},
  {"ns2", "192.168.0.3"},
  {"ns1", "192.168.0.2"}
])
[
  {"ns1", "192.168.0.2"},
  {"ns2", "192.168.0.3"},
  {"ns3", "192.168.0.4"}
]
iex> DualMap.get(dm, :ip, "192.168.0.4")
"ns3"

get_map(dual_map, master_key)

@spec get_map(t(), master_key :: any()) :: map()

Return the complete internal map indexed by master_key.

Examples

iex> dm = DualMap.new({:hostname, :ip}, [
  {"ns3", "192.168.0.4"},
  {"ns2", "192.168.0.3"},
  {"ns1", "192.168.0.2"}
])
[
  {"ns1", "192.168.0.2"},
  {"ns2", "192.168.0.3"},
  {"ns3", "192.168.0.4"}
]
iex> DualMap.get_map(dm, :hostname)
%{
  "ns1" => "192.168.0.2",
  "ns2" => "192.168.0.3",
  "ns3" => "192.168.0.4"
}

has?(dual_map, key_value)

@spec has?(t(), key :: any()) :: boolean()

Checks if key exists within DualMap.

Examples

iex> dm = DualMap.new({:hostname, :ip}, [
  {"ns3", "192.168.0.4"},
  {"ns2", "192.168.0.3"},
  {"ns1", "192.168.0.2"}
])
[
  {"ns1", "192.168.0.2"},
  {"ns2", "192.168.0.3"},
  {"ns3", "192.168.0.4"}
]
iex> DualMap.has?(dm, "192.168.0.4")
true
iex> DualMap.has?(dm, "ns2")
true
iex> DualMap.has?(dm, "ns5")
false

keys(dual_map, master_key)

@spec keys(t(), master_key :: any()) :: list()

Return a list with all the keys of the internal map indexed by master_key.

Examples

iex> dm = DualMap.new({:hostname, :ip}, [
  {"ns3", "192.168.0.4"},
  {"ns2", "192.168.0.3"},
  {"ns1", "192.168.0.2"}
])
iex> DualMap.keys(dm, :hostname)
["ns1", "ns2", "ns3"]

member?(dual_map, arg)

@spec member?(t(), key_value :: {any(), any()}) :: boolean()

Checks if the pair key_value (tuple size 2) exists within DualMap either as key => value or as value => key.

Examples

iex> dm = DualMap.new({:hostname, :ip}, [
  {"ns3", "192.168.0.4"},
  {"ns2", "192.168.0.3"},
  {"ns1", "192.168.0.2"}
])
[
  {"ns1", "192.168.0.2"},
  {"ns2", "192.168.0.3"},
  {"ns3", "192.168.0.4"}
]
iex> DualMap.member?(dm, {"192.168.0.4", "ns3"})
true
iex> DualMap.member?(dm, {"ns3", "192.168.0.4"})
true
iex> DualMap.member?(dm, {"ns1", "192.168.0.4"})
false

new(arg)

@spec new(master_keys :: {master_key1 :: any(), master_key2 :: any()}) :: t()

Returns an empty DualMap struct. The order of the master keys are important for posterior operations with the struct.

Examples

iex> DualMap.new({:hostname, :ip})
[]

new(master_keys, values)

@spec new(
  {master_key1 :: any(), master_key2 :: any()},
  {any(), any()} | [tuple()]
) :: t()

Returns a DualMap struct initialized with the values indicated in the second argument. As the new/1 function, the order of the master keys are important for posterior operations with the struct.

Examples

# Initializing with one pair of values
iex> DualMap.new({:hostname, :ip}, {"ns1", "192.168.0.2"})
[{"ns1", "192.168.0.2"}]

# Initializing with more than one pair of values
iex> DualMap.new({:hostname, :ip}, [
  {"ns3", "192.168.0.4"},
  {"ns2", "192.168.0.3"},
  {"ns1", "192.168.0.2"}
])
[
  {"ns1", "192.168.0.2"},
  {"ns2", "192.168.0.3"},
  {"ns3", "192.168.0.4"}
]

put(dual_map, master_key1, arg3)

@spec put(t(), master_key :: any(), {key :: any(), value :: any()} | [tuple()]) :: t()

Insert or replace one or more pairs of datas in a DualMap. If the third parameters is a list of tuples, every one is inserted/replaced in the DualMap secuentialy. With this function you need pass the a master_key to indicate which value of the tuple will be interpreted as key and which one as value.

Examples

iex> dm = DualMap.new({:hostname, :ip})
[]
# Inserting/replacing many
iex> DualMap.put(dm, :ip, [
  {"192.168.0.4", "ns3"},
  {"192.168.0.3", "ns2"},
  {"192.168.0.2", "ns1"}
])
[
  {"ns1", "192.168.0.2"},
  {"ns2", "192.168.0.3"},
  {"ns3", "192.168.0.4"}
]
Or inserting just one
iex> DualMap.put(dm, :ip, {"192.168.0.4", "ns3"})
[{"ns3", "192.168.0.4"}]

put_ordered(dual_map, pair)

@spec put_ordered(t(), {any(), any()} | [tuple()]) :: t()

This function is similar to put/3 but you does not need pass a master key because the function will assume that you are sending the keys and values in the same order as you defined when you created the DualMap with new/1 or new/2.

Examples

iex> dm = DualMap.new({:hostname, :ip})
[]
iex> DualMap.put_ordered(dm, [
  {"ns3", "192.168.0.4"},
  {"ns2", "192.168.0.3"},
  {"ns1", "192.168.0.2"}
])
[
  {"ns1", "192.168.0.2"},
  {"ns2", "192.168.0.3"},
  {"ns3", "192.168.0.4"}
]

put_ordered(dual_map, value1, value2)

@spec put_ordered(t(), any(), any()) :: t()

to_list(dual_map, option \\ nil)

Return a list of the pairs {key, value} taking the map indexed by the first master_key defined with new/1 or new/2. This function is used by inspect to print the DualMap.

If you also pass an option :pairs_inverted, the list will have the pairs with key/value inverted because will take the internal map indexed by the second master_key defined with new/1 or new/2.

values(dual_map, master_key)

@spec values(t(), master_key :: any()) :: list()

Return a list with all the values of the internal map indexed by master_key.

Examples

iex> dm = DualMap.new({:hostname, :ip}, [
  {"ns3", "192.168.0.4"},
  {"ns2", "192.168.0.3"},
  {"ns1", "192.168.0.2"}
])
[
  {"ns1", "192.168.0.2"},
  {"ns2", "192.168.0.3"},
  {"ns3", "192.168.0.4"}
]
iex> DualMap.values(dm, :hostname)
["192.168.0.2", "192.168.0.3", "192.168.0.4"]