What is the idomatic way to process tree data structures in Elixir?
I have a database table that holds a ton of rows which define a hierarchy by an attribute called parent_id
.
Solution 1: Huge Map
A Tree module that transforms the rows into a map. For each row, it contains the mapping froim the id attribute of each row to something like %{item: row, children: [children_ids...], parent: parent_id}
. Also, a list of root_ids is stored, for rows without a parent_id. So, the structure returned looks like:
%{ nodes: %{
1 => %{item: %{...}, children: [2, 3], parent: nil},
2 => %{item: %{...}, children: [], parent: 1},
3 => %{item: %{...}, children: [4], parent: 1},
...,
roots: [1]}
The module has functions to get the root nodes and to fetch nodes by their id from the map. The same way, it fetches the children for a given node.
Solution 2: Using Agents
Instead of a huge map, I tried to use an Agent for every node in the tree. Its a process holding quite the same data as above, but it is easier to set up the structure from the initial list of rows.
%{ roots: [#PID<0.122.0>] }
and an Agents with their state like
%{item: %{}, children: [PID#<0.123.0>, PID#<0.124.0>], parent: nil} # PID#<0.122.0>
%{item: %{}, children: [], parent: PID#<0.122.0>} # PID#<0.123.0>
I can even map a function over a tree to transform all the nodes while keeping the structure. But here I can shoot in my foot: If I just map a function f that transforms the agents item state, I get the behaviour of a mutable data structure.
So I did not transform the state of the agent, but created a new one with the transformed item and the parent and children properly set up.