I made an algorithm to flatten a map into a single keypath => value map, based on @benwilson512’s code from this topic.
However when I run it on a medium-sized map (about 150 keys in total, up to 5 levels in map nesting), the beam blows up due to memory errors.
I must be doing very stupid but I don’t see directly what’s wrong…
defmodule FlatMap do
def flatten(map, opts \\ [join: true])
def flatten(map, opts) when is_map(map) do
map
|> Map.to_list()
|> do_flatten([], [])
|> Enum.map(fn {k, v} ->
k = Enum.reverse(k)
case opts[:join] do
true -> {Enum.join(k, "."), v}
false -> {k, v}
end
end)
|> Map.new()
end
defp do_flatten([], acc, _), do: List.flatten(acc)
defp do_flatten([{k, v} | rest], acc, path) when is_map(v) do
v =
v |> Map.to_list()
flattened_subtree = do_flatten(v, acc, [k | path])
do_flatten(rest, [flattened_subtree, acc], path)
end
defp do_flatten([{k, v} | rest], acc, path) do
do_flatten(rest, [{[k | path], v} | acc], path)
end
end
Obviously this algorithm is not tailcall optimized but for my limits that should not matter that much… or does it?