Starting from a list of "tree paths", for example:
[["a", "b", "c"], ["a", "b", "e"], ["f", "g"]]
I would like to build a forest ([Tree]
):
a
|_ b
|_ c
|_ e
f
|_ g
This is my attempt so far. I have been constructing the building blocks in order to assemble the final solution:
module Main where
import Data.Tree
insertPath :: Eq a => [a] -> [Tree a] -> [Tree a]
insertPath [] ts = ts
insertPath (y:ys) [] = Node y [] : []
insertPath (y:ys) ((Node x ts):ts')
| y /= x = Node x ts : insertPath ys ts'
| otherwise = Node x (insertSubTrees ys ts) : insertPath ys ts'
insertSubTrees :: Eq a => [a] -> [Tree a] -> [Tree a]
insertSubTrees [] ts = ts
insertSubTrees (y:ys) [] = insertSubTrees ys [Node y []]
insertSubTrees (y:ys) (t:ts) = undefined
My questions are:
Tree
or a list of Tree
?buildForest :: Eq a => [a] -> [Tree a] -> [Tree a]
function ?I think you overcomplicate things: if you reach the end of the path, we simply are done. So we can do this in one function:
insertPath :: Eq a => [a] -> [Tree a] -> [Tree a]
insertPath [] = id
insertPath (p : ps) = go
where
go [] = [Node p (insertPath ps [])]
go (n@(Node x xs) : ns)
| p == x = Node x (insertPath ps xs) : ns
| otherwise = n : go ns
You can then generate the entire forest with a list of paths with:
insertPaths :: Eq a => [Tree a] -> [[a]] -> [Tree a]
insertPaths = foldl (flip insertPath)
With the sample data, we thus generate a forest with:
ghci> insertPaths [] [["a", "b", "c"], ["a", "b", "e"], ["f", "g"]]
[Node {rootLabel = "a", subForest = [Node {rootLabel = "b", subForest = [Node {rootLabel = "c", subForest = []},Node {rootLabel = "e", subForest = []}]}]},Node {rootLabel = "f", subForest = [Node {rootLabel = "g", subForest = []}]}]