The reduce solution is definitely the production-quality answer. However, since you mentioned the difficulty you are having with functional programming, consider the 'long-hand' version of the reduce:
defmodule MapMerger do # The api function takes a list of maps, and returns them merged together. def merge(list_of_maps) do # This is written with a second function to hopefully be easier to follow; # these two functions could be collapsed using a default parameter # for the accumulator. do_merge(list_of_maps, %{}) end # This is the base case, which will match after all maps have been processed # and the list is empty: defp do_merge([], acc), do: acc # Next comes the actual iterator; we pull head (the first item in the list), # process it, then recurse on the rest of the list and an updated accumulator defp do_merge([head|rest], acc) do updated_acc = Map.merge(acc, head) do_merge(rest, updated_acc) end end
Once you can follow this, reduce should easier to think about- it doesn't modify anything, it just keeps recursing with new parameters that happen to be updated versions of the old parameters. My production code usually uses reduce for small work like this, but when the operation inside the reduce is complicated, I usually decompose the reduce to a proper function that is easier to reason about, and easier to mark up with comments.
From your original question:
In other language I would define an empty map and iterate through the list and fill the map
Note that this is a reasonable description of how the merge and do_merge functions above work. You aren't as far away from thinking functionally as you believe.
Enum.reduce. :) All of the other functions in the Enum module are implemented on top of it. I can post the complete answer but I think you would learn more if you tried to solve it Enum.reduce first.