Reputation: 9008
How could a list of maps like some_maps = [%{"test" => [1]}, %{"test2" => [2]}, %{"test" => [3]}]
be converted to one huge single map with it's values merged?
single_map = %{"test" => [1, 3], "test2" => [2]}
Since I cannot modify a map within an iteration like for
I dont know how to build this map
In other language I would define an empty map and iterate through the list and fill the map but functionally thinking I dont see how I could do this.
Upvotes: 2
Views: 3950
Reputation: 1631
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.
Upvotes: 5
Reputation: 1637
Here's one way to do it:
Enum.reduce(some_maps, fn x, y ->
Map.merge(x, y, fn _k, v1, v2 -> v2 ++ v1 end)
end)
Upvotes: 13