November 30, 2007
•
ListToTree Haskell Module
> {-# OPTIONS_GHC -fglasgow-exts #-}
> module ListToTree
> ( Tree ( Tree )
> , pairListToTreeList
> , EmptyNode
> , pairListToTree
> )
> where
> import Data.Generics
There was a thread on haskell-cafe about doing this exact task. The code I wrote was embarassingly complicated compared to their simple answer, which inspired the below code. Thanks to Cale G. and Chris K.
> data Tree a = Tree a [Tree a] deriving (Show, Eq, Data, Typeable)
Actual exported function
> pairListToTreeList :: [(Int, a)] -> [Tree a] > pairListToTreeList [] = [] > pairListToTreeList ((n,a):aa) = > let (kids, sibs) = span (\x-> fst x > n) aa > in (Tree a (pairListToTreeList kids)) : pairListToTreeList sibs
Or straight to a tree, if an empty node for that tree type has meaning.
> class EmptyNode a where > empty :: a > > instance EmptyNode [a] where > empty = [] > > pairListToTree :: EmptyNode a => [(Int, a)] -> Tree a > pairListToTree list = Tree empty (pairListToTreeList list)
Example test code
> test = do print $ pairListToTree list > > list :: [(Int, String)] > list = [(1, "topA"), > (2, "secondC"), > (2, "secondD"), > (3, "thirdG"), > (3, "thirdH"), > (2, "secondE"), > (1, "topB"), > (2, "secondF")]
yields
< Tree "" [Tree "topA" [Tree "secondC" [], < Tree "secondD" < [Tree "thirdG" [], < Tree "thirdH" []], < Tree "secondE" []] < , Tree "topB" [Tree "secondF" []]]
In JavaScript, this could be done like this:
// Tree data structure
class Tree {
constructor(value, children = []) {
this.value = value;
this.children = children;
}
}
// Converts a list of {level, text} objects to a list of Tree nodes
function pairListToTreeList(pairs, cons = (x, y) => new Tree(x, y)) {
if (pairs.length === 0) return [];
const [{ level, text }, ...rest] = pairs;
const kids = [];
let i = 0;
// Find all children (where level > current level)
while (i < rest.length && rest[i].level > level) {
kids.push(rest[i]);
i++;
}
const sibs = rest.slice(i);
return [
cons(text, pairListToTreeList(kids, cons)),
...pairListToTreeList(sibs, cons)
];
}
// Example usage:
const input = [
{ level: 1, text: 'a' },
{ level: 2, text: 'b' },
{ level: 3, text: 'c' },
{ level: 1, text: 'd' }
];
console.log(pairListToTreeList(input));
let str = pairListToTreeList(input,
function(x, y) { return `<ul>\n<li>${x}</li>\n${y.join('\n')}</ul>` }
).join('');
console.log(str);
This prints:
[
Tree { value: 'a', children: [ [Tree...] ] },
Tree { value: 'd', children: [] }
]
Which makes HTML that renders like this:
- a
- b
- c
- d