Deep merge map with Enum.map

lapinkoira Source

I have this functions:

defmodule TestQuery do

  def build_query() do
    Enum.map(["test1", "test2", "hello"], fn item ->
      query(item)
    end)
  end

  def query(item) do
    case item do
      "test1" -> %{"test1" => 1}
      "test2" -> %{"test2" => 2}
      "hello" -> %{"hello" => 3}
    end
  end

end

And build_query returns a list of maps like this:

iex(2)> TestQuery.build_query
[%{"test1" => 1}, %{"test2" => 2}, %{"hello" => 3}]

But is there a way to just return a single map like this?

%{"test1" => 1, "test2" => 2, "hello" => 3}

Should I use other method instead Enum.map?

I know I can after having the list Map.reduce and Map.merge the list but I was wondering if it can be achieved in one step.

elixir

Answers

answered 6 months ago Dogbert #1

If query/1 will always return one pair of key/value, you can use for with into: %{} and return a tuple from query/1:

defmodule TestQuery do
  def build_query do
    for item <- ["test1", "test2", "hello"], into: %{}, do: query(item)
  end

  def query(item) do
    case item do
      "test1" -> {"test1", 1}
      "test2" -> {"test2", 2}
      "hello" -> {"hello", 3}
    end
  end
end

IO.inspect TestQuery.build_query()

Output:

%{"hello" => 3, "test1" => 1, "test2" => 2}

If it can return multiple items, you can merge the reduce step with the map and do it in one pass like this:

defmodule TestQuery do
  def build_query do
    Enum.reduce(["test1", "test2", "hello"], %{}, fn item, acc ->
      Map.merge(acc, query(item))
    end)
  end

  def query(item) do
    case item do
      "test1" -> %{"test1" => 1}
      "test2" -> %{"test2" => 2}
      "hello" -> %{"hello" => 3}
    end
  end
end

IO.inspect TestQuery.build_query()

The output is the same as above.

comments powered by Disqus