Anthony W
Anthony W

Reputation: 1327

Enumerating an Elixir HashDict structure

I'm a newbie to Elixir and am trying to write a GenServer that stores key, value pairs in a HashDict. Storing a compound key and value is fine. here's the code:

  #Initialise the HashDict GenServer.start_link
  def init(:ok) do
    {:ok, HashDict.new}
  end

  #Implement the server call back for GenServer.cast 
  def handle_cast({:add, event}, dict) do
    {foo, bar, baz, qux} = event

    key = %{key1: foo, key2: bar}
    value = %{val1: baz, val2: qux}

    {:noreply, HashDict.put(dict, key, value) }
  end

All good. But I'm having trouble implementing the handle_call behaviour that I want. So here I'd like:

  1. For a given key1 value, retrieve all corresponding value entries in HashDict. This will mean ignoring the value for key2 (so kind of a select all).
  2. Having returned all the val2s, add them all up (assuming they are integers, ignoring val1) to give an overall sum.

So I've got this far:

def handle_call({:get, getKey}, _from, dict) do
  key = %{key1: getKey, key2: _}
  {:reply, HashDict.fetch(dict, key), dict}
end

This doesn't work, as it's not possible to pattern match on _. Presumably I would use some kind of Enumeration over the map such as the following to achieve my second objective:

Enum.map(mymap, fn {k, v} -> v end)|> Enum.sum{}

But I can't seem to quite crack the syntax to achieve my two aims. Thanks for any help!

Upvotes: 0

Views: 206

Answers (1)

potatosalad
potatosalad

Reputation: 4887

If I understand your question correctly, the following should accomplish what you are wanting to do:

def handle_call({:get, getKey}, _from, dict) do
  sum = Enum.reduce(dict, 0, fn
    ({%{key1: key1}, %{val2: val2}}, acc)
        when key1 === getKey
        and is_integer(val2) ->
      val2 + acc
    (_, acc) ->
      acc
  end)
  {:reply, sum, dict}
end

See the documentation of Enum.reduce/3 for more information.

Upvotes: 1

Related Questions