The main problem with building a nested tree from e.g. maps is that insertion of a child of some element will take O(log n). If you already know that each node has an unique ID (either because they are incrementing integers, or because they are an UUID), then you can instead go for a ‘flat’ approach in which you have a map where the keys are the nodes IDs, and each node contains a parent_id
field that points to another node.
Note that it is possible to store any kind of graph in this kind of flat representation, including graphs with cycles. There is nothing preventing this from happening, so care needs to be taken while inserting/updating.
building such a tree now takes O(n) instead of O(n log n). However, finding all children of a certain parent will take O(n), since we need to check the parent IDs for all nodes.
As for your questions:
Correct. But if you build a ‘nested set’, then order should not matter.
Correct. It is unfortunate that Elixir does not allow Keyword to be used with string keys. I do not know the rationale behind this restriction.
This is definitely not the right way, since spawning a process for each node will take memory, and your data structure is a ‘flat data’ one, without any kind of automation.
I think using maps remains the best way. Either a flat map or a nested map in which the child nodes are part of the parent (From the example in your first post it seems that you are doing the opposite, where the parent nodes are part of the child. I believe this would create n!
nodes in the internal representation, which would explain why it is so slow).
Maybe interesting to you is that I built Tensor, the sparse vector/matrix/tensor library on top of sparse rose trees, in other words: nested maps:
Tensor.new([[[1,2],[3,4]],[[5,6],[7,8]]], [2, 2,2]) |> IO.inspect(structs: false)
%{__struct__: Tensor,
contents: %{0 => %{0 => %{0 => 1, 1 => 2}, 1 => %{0 => 3, 1 => 4}},
1 => %{0 => %{0 => 5, 1 => 6}, 1 => %{0 => 7, 1 => 8}}},
dimensions: [2, 2, 2], identity: 0}