DualMap (dual_map_ex v0.1.0)

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

Delete a pair of datas and returns the DualMap without that pair. The pair is found using looking for key1 (third parameter) in the the map that has the master_key1 (second parameter) as key.

Just the same that [delete/3](#delete/3) but you can pass a list of keys to delete.

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 the 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](#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 specified when you created the DualMap with [new/1](#new/1) or [new/2](#new/2).

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()

delete(dual_map, master_key1, key1)

@spec delete(t(), master_key1 :: any(), key1 :: any()) :: t()

Delete a pair of datas and returns the DualMap without that pair. The pair is found using looking for key1 (third parameter) in the the map that has the master_key1 (second parameter) as 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_key1 :: any(), list()) :: t()

Just the same that [delete/3](#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()

fetch(dual_map, master_key, key)

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

fetch!(dual_map, master_key, key)

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

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

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

get_map(dual_map, master_key)

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

has?(dual_map, key_value)

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

keys(dual_map, master_key)

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

member?(dual_map, arg)

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

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> dm = 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 the 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](#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 specified when you created the DualMap with [new/1](#new/1) or [new/2](#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)

values(dual_map, master_key)

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