我需要从数据库行构建一个树。更具体地说,我有一张包含会计科目表的表格。
我不是以递归方式查询表,而是想在一步中加载所有表的信息,包含id和parentIds的帐户行,然后从那里构建树。
其中一个问题是帐户行没有任何顺序,即。在遇到父母之前,我可能会遇到一个孩子。
我认为这个问题非常通用,所以我认为甚至可能已经有了一个haskell库。
有人可以帮忙吗?
答案 0 :(得分:2)
正如尼基塔所说,你的真正问题是什么?
您不提供任何数据类型,树密钥分类,......
无论如何,这段代码可以帮助你思考你的问题......
data Tree a = Node a [Tree a] deriving Show
db = [(0, 1)
,(1, 2)
,(1, 3)
,(2, 4)
,(2, 6)
,(3, 5)
]
rootTree = Node 0 []
insert parent child (Node key childs) =
Node key $ if key == parent then Node child []:childs
else map (insert parent child) childs
insertFromDB rows = foldl insertRow rootTree rows
where insertRow tree (parent, child) = insert parent child tree
如果你不能得到有序数据,你可以命令它搜索父母,下一个函数计算每个节点的深层次(具有相同的db
数据)
calculateDeepLevel db = compute 0 roots
where roots = filter (not.flip elem snds) fsts
fsts = nub $ map fst db
snds = map snd db
compute level parents = map (\n -> (n, level)) parents ++
concatMap (addChilds (level + 1)) parents
addChilds level node = compute level $ map snd $ filter ((node==).fst) db
使用calculateDeepLevel
,您可以计算有序db
版本,并且从db
的无序且无根(无0节点)版本开始计算0。
答案 1 :(得分:2)
首先是一些导入,
import qualified Data.Map as M
import qualified Data.Tree as T
import Data.List (foldl')
import Control.Arrow ((&&&))
import Data.Maybe (fromMaybe)
接下来,我们假设我们的记录具有id和可选的父id(根节点没有父节点),并带有一些值:
data Rec a = Rec { recId :: Int
, recParentId :: Maybe Int
, recValue :: a
}
没有什么可以阻止多个节点拥有Nothing
父ID,因此我们可能会找到多个树,因此我们将列表转换为树的函数可能如下所示:
toTree :: [Rec a] -> [T.Tree a]
toTree rs = ts where
首先,让我们构建一个从可选父ID到具有该父ID的记录列表的映射:
-- gs :: M.Map (Maybe Int) [Rec a]
gs = foldl' f M.empty rs where
f m r = M.insertWith (const (r:)) (recParentId r) [r] m
接下来,让我们从虚拟根节点开始展开一个树,其中的子节点将是我们感兴趣的树的根。请注意,虚根节点没有值,因此我们使用{{1} }:
undefined
-- t :: T.Tree a
t = T.unfoldTree mkNode (undefined, Nothing)
函数传递了我们要构建的节点的值和id。它使用我们之前构造的mkNode
返回值和子值/ id对的列表:
Map
最后,我们可以丢弃虚拟根节点,并将其直接子节点作为我们感兴趣的树的根源返回:
-- mkNode :: (a, Maybe Int) -> (a, [(a, Maybe Int)])
mkNode (a, i) = (a, map (recValue &&& Just . recId)
. fromMaybe []
. M.lookup i $ gs)
这是一个测试:
ts = T.subForest t
生成:
main = mapM_ (putStrLn . T.drawTree)
$ toTree [ Rec 0 Nothing "rootA"
, Rec 1 (Just 0) "rootA.childA"
, Rec 2 (Just 0) "rootA.childB"
, Rec 3 (Just 1) "rootA.childA.childA"
, Rec 4 (Just 1) "rootA.childA.childB"
, Rec 5 (Just 2) "rootA.childB.childA"
, Rec 6 (Just 2) "rootA.childB.childB"
, Rec 7 Nothing "rootB"
, Rec 8 (Just 7) "rootB.childA"
, Rec 9 (Just 7) "rootB.childB"
, Rec 10 (Just 8) "rootB.childA.childA"
, Rec 11 (Just 8) "rootB.childA.childB"
, Rec 12 (Just 9) "rootB.childB.childA"
, Rec 13 (Just 9) "rootB.childB.childB"
]
答案 2 :(得分:1)
StackOverflow的答案质量几乎完全取决于您提供的问题的质量。如果你想得到一个包含一些代码的答案,你应该在你的问题中提供一些代码,如果你想获得一些特定库的答案,那么请参考它。
目前您的问题非常模糊,我只能回答您需要使用类似Data.Map
的结构来首先累积中间结果,然后通过查询此中间数据结构重新排列它们。正如文档所表示的那样,其大多数访问函数的复杂性为O(log n)
,这非常有效。
您不应该期望来自任何数据库库的这种功能,因为问题太具体了。