88 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Haskell
		
	
	
	
	
	
			
		
		
	
	
			88 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Haskell
		
	
	
	
	
	
| module Hledger.Utils.Tree where
 | |
| 
 | |
| -- import Data.Char
 | |
| import Data.List (foldl')
 | |
| import qualified Data.Map as M
 | |
| import Data.Tree
 | |
| -- import Text.Parsec
 | |
| -- import Text.Printf
 | |
| 
 | |
| import Hledger.Utils.Regex
 | |
| -- import Hledger.Utils.UTF8IOCompat (error')
 | |
| 
 | |
| -- standard tree helpers
 | |
| 
 | |
| root = rootLabel
 | |
| subs = subForest
 | |
| branches = subForest
 | |
| 
 | |
| -- | List just the leaf nodes of a tree
 | |
| leaves :: Tree a -> [a]
 | |
| leaves (Node v []) = [v]
 | |
| leaves (Node _ branches) = concatMap leaves branches
 | |
| 
 | |
| -- | get the sub-tree rooted at the first (left-most, depth-first) occurrence
 | |
| -- of the specified node value
 | |
| subtreeat :: Eq a => a -> Tree a -> Maybe (Tree a)
 | |
| subtreeat v t
 | |
|     | root t == v = Just t
 | |
|     | otherwise = subtreeinforest v $ subs t
 | |
| 
 | |
| -- | get the sub-tree for the specified node value in the first tree in
 | |
| -- forest in which it occurs.
 | |
| subtreeinforest :: Eq a => a -> [Tree a] -> Maybe (Tree a)
 | |
| subtreeinforest _ [] = Nothing
 | |
| subtreeinforest v (t:ts) = case (subtreeat v t) of
 | |
|                              Just t' -> Just t'
 | |
|                              Nothing -> subtreeinforest v ts
 | |
| 
 | |
| -- | remove all nodes past a certain depth
 | |
| treeprune :: Int -> Tree a -> Tree a
 | |
| treeprune 0 t = Node (root t) []
 | |
| treeprune d t = Node (root t) (map (treeprune $ d-1) $ branches t)
 | |
| 
 | |
| -- | apply f to all tree nodes
 | |
| treemap :: (a -> b) -> Tree a -> Tree b
 | |
| treemap f t = Node (f $ root t) (map (treemap f) $ branches t)
 | |
| 
 | |
| -- | remove all subtrees whose nodes do not fulfill predicate
 | |
| treefilter :: (a -> Bool) -> Tree a -> Tree a
 | |
| treefilter f t = Node
 | |
|                  (root t)
 | |
|                  (map (treefilter f) $ filter (treeany f) $ branches t)
 | |
| 
 | |
| -- | is predicate true in any node of tree ?
 | |
| treeany :: (a -> Bool) -> Tree a -> Bool
 | |
| treeany f t = f (root t) || any (treeany f) (branches t)
 | |
| 
 | |
| -- treedrop -- remove the leaves which do fulfill predicate.
 | |
| -- treedropall -- do this repeatedly.
 | |
| 
 | |
| -- | show a compact ascii representation of a tree
 | |
| showtree :: Show a => Tree a -> String
 | |
| showtree = unlines . filter (regexMatches "[^ \\|]") . lines . drawTree . treemap show
 | |
| 
 | |
| -- | show a compact ascii representation of a forest
 | |
| showforest :: Show a => Forest a -> String
 | |
| showforest = concatMap showtree
 | |
| 
 | |
| 
 | |
| -- | An efficient-to-build tree suggested by Cale Gibbard, probably
 | |
| -- better than accountNameTreeFrom.
 | |
| newtype FastTree a = T (M.Map a (FastTree a))
 | |
|   deriving (Show, Eq, Ord)
 | |
| 
 | |
| emptyTree = T M.empty
 | |
| 
 | |
| mergeTrees :: (Ord a) => FastTree a -> FastTree a -> FastTree a
 | |
| mergeTrees (T m) (T m') = T (M.unionWith mergeTrees m m')
 | |
| 
 | |
| treeFromPath :: [a] -> FastTree a
 | |
| treeFromPath []     = T M.empty
 | |
| treeFromPath (x:xs) = T (M.singleton x (treeFromPath xs))
 | |
| 
 | |
| treeFromPaths :: (Ord a) => [[a]] -> FastTree a
 | |
| treeFromPaths = foldl' mergeTrees emptyTree . map treeFromPath
 | |
| 
 | |
| 
 |