defmodule Demo do
def paths(tree) do
paths(tree, [], [])
end
defp paths(tree, parent_path, paths) do
{_,paths} = Enum.reduce(tree, {parent_path, paths}, &descend/2)
paths
end
defp descend({key, value}, {parent_path, paths}) do
paths =
if is_map(value) do
paths(value, [key|parent_path], paths)
else
[:lists.reverse([key|parent_path])|paths]
end
{parent_path, paths}
end
def run(tree) do
tree
|> Demo.paths()
|> IO.inspect()
end
end
Demo.run(%{})
Demo.run(%{k11: 11})
Demo.run(%{k1: %{k11: 11}})
Demo.run(%{k1: %{k11: 11}, k2: 2})
Demo.run(%{k1: %{k11: 11}, k2: %{k21: 21} })
Demo.run(%{k1: %{k11: 11}, k2: %{k21: 21, k22: 22}})
$ elixir demo.exs
[]
[[:k11]]
[[:k1, :k11]]
[[:k2], [:k1, :k11]]
[[:k2, :k21], [:k1, :k11]]
[[:k2, :k22], [:k2, :k21], [:k1, :k11]]
defmodule Demo do
def paths(tree),
do: paths(Map.to_list(tree), [], [], [])
defp paths([], _, [], paths),
do: paths
defp paths([], _, [{parent, others} | rest], paths),
do: paths(others, parent, rest, paths)
defp paths([{key, value} | others], parent, rest, paths) when is_map(value),
do: paths(Map.to_list(value), [key | parent], [{parent, others} | rest], paths)
defp paths([{key, _} | others], parent, rest, paths),
do: paths(others, parent, rest, [:lists.reverse([key | parent]) | paths])
def run(tree) do
tree
|> Demo.paths()
|> IO.inspect()
end
end
Demo.run(%{})
Demo.run(%{k1: 1})
Demo.run(%{k1: %{k11: 11}})
Demo.run(%{k1: %{k11: 11}, k2: 2})
Demo.run(%{k1: %{k11: 11}, k2: %{k21: 21}})
Demo.run(%{k1: %{k11: 11}, k2: %{k21: 21, k22: 22}})
Demo.run(%{k1: %{k11: %{k111: 111, k112: 112}, k12: 12}, k2: %{k21: 21, k22: 22}})
$ elixir demo.exs
[]
[[:k1]]
[[:k1, :k11]]
[[:k2], [:k1, :k11]]
[[:k2, :k21], [:k1, :k11]]
[[:k2, :k22], [:k2, :k21], [:k1, :k11]]
[[:k2, :k22], [:k2, :k21], [:k1, :k12], [:k1, :k11, :k112], [:k1, :k11, :k111]]
$