Reputation: 1010
How do I achieve the same result shown in this question using Haskell and non-binary trees, such as Data.Tree
? Considering the record NodeData { nodeID :: String , parentID :: String, value :: a }
to store data, and Data.Tree
for the tree type, a tree would be:
Node $ NodeData "id" "parent" (value :: a) (children :: Forest (NodeData a)) :: Tree (NodeData a)
Now how could I update value
based on the node's children's value
and its own? The input table would be a list [NodeData]
. NodeData
and the ids could be made an instance of Eq
, but not Ord
.
Upvotes: 1
Views: 484
Reputation: 91857
I see no particularly clever single-pass solution to this. You simply have to bite the bullet and do two passes: one pass creates an index of the form Map Id [Node]
, listing all the children of each node. Then a second pass consumes this index and reconstitutes it into a Forest a
. Note it's not a Tree a
, because there's no value to put at the root, and also because for all we know there are multiple roots.
import qualified Data.Map.Lazy as M
import qualified Data.Tree as T
newtype Id = Id Int deriving (Eq, Show, Ord)
data Node a = Node {id, parent :: Id, value :: a} deriving Show
input :: [Node String]
input = [ Node (Id 1) (Id 0) "1"
, Node (Id 2) (Id 1) "1.1"
, Node (Id 3) (Id 0) "2"
, Node (Id 4) (Id 2) "1.1.1"
, Node (Id 5) (Id 3) "2.1"
, Node (Id 6) (Id 1) "1.2"
]
index :: [Node a] -> M.Map Id [Node a]
index m = M.fromListWith (++) $ do
n@(Node this parent v) <- m
pure (parent, [n])
recombine :: M.Map Id [Node a] -> T.Forest a
recombine m = go (Id 0) -- Implied root, but a more thorough solution would be explicit
where go root = [ T.Node v (go idx)
| Node idx p v <- M.findWithDefault [] root m
]
After this, we have the tree we wanted:
> putStr . T.drawForest . recombine . index $ input
2
|
`- 2.1
1
|
+- 1.2
|
`- 1.1
|
`- 1.1.1
Upvotes: 3