-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSpecifyTree.hs
81 lines (62 loc) · 2.38 KB
/
SpecifyTree.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
module SpecifyTree where
import Control.Applicative
import Data.Map (Map, fromList, fromListWith, findWithDefault, (!))
import Data.Tree
import Text.JSON
import Squarify (TreeMapTree(..))
type NodeID = Int
type RankID = Int
type ParentID = Maybe NodeID
data SpecifyTreeNode = SpecifyTreeNode {
nodeId :: NodeID,
rankId :: RankID,
parentId :: ParentID,
name :: String,
fullName :: String,
count :: Int
} deriving Show
data SpecifyTree = SpecifyTree [SpecifyTreeNode] deriving Show
instance JSON SpecifyTreeNode where
readJSON (JSArray row) = do
nodeId <- getVal row 0
rankId <- getVal row 1
parentId <- case row !! 2 of
JSNull -> Ok Nothing
v -> Just <$> readJSON v
name <- getVal row 3
fullName <- getVal row 4
count <- getVal row 5
return $ SpecifyTreeNode nodeId rankId parentId name fullName count
where getVal vals n = readJSON $ vals !! n
showJSON = undefined
instance JSON SpecifyTree where
readJSON (JSArray rows) = SpecifyTree <$> mapM readJSON rows
showJSON = undefined
type NodesByParent = Map ParentID [SpecifyTreeNode]
groupByParent :: SpecifyTree -> NodesByParent
groupByParent (SpecifyTree nodes) =
fromListWith (++) [(parentId n, [n]) | n <- nodes]
type NodesById = Map NodeID SpecifyTreeNode
nodesById :: SpecifyTree -> NodesById
nodesById (SpecifyTree nodes) = fromList [(nodeId n, n) | n <- nodes]
makeTree :: NodesById -> NodesByParent -> Maybe NodeID -> TreeMapTree
makeTree byId byParent nId = case children of
[child] | thisSize == 0 -> child
children | thisSize > 0 -> Node (size, name) $ (Node (thisSize, name) []):children
children -> Node (size, name) children
where size = thisSize + sum [size | (Node (size, _) _) <- children]
(thisSize, name) = case nId of
Nothing -> (0, "")
Just nId -> (count n, fullName n)
where n = byId ! nId
children = map (treeFromNodeId . Just . nodeId) childNodes
treeFromNodeId nId = makeTree byId byParent nId
childNodes = findWithDefault [] nId byParent
specifyToTree :: SpecifyTree -> TreeMapTree
specifyToTree specifyTree = makeTree byId byParent Nothing
where byId = nodesById specifyTree
byParent = groupByParent specifyTree
treeFromJson :: String -> TreeMapTree
treeFromJson s = case (decode s) of
Ok st -> specifyToTree st
_ -> error "couldn't parse json"