我正在尝试使用F#建模一个简单的树结构,并且不禁认为我这样做非常糟糕:
我的树本质上是一个叶子列表(最终会保存到数据库表中)。我有一个函数getChildren接收一个叶子NodeID并递归返回该叶子的所有子节点。
open System.Collections.Generic
type leaf = { nodeID : int; nodeDescr : string; parentID : int option}
let myTree = [ { nodeID = 0; nodeDescr = "Root"; parentID = None };
{ nodeID = 1; nodeDescr = "Mechanical"; parentID = Some(0) } ;
{ nodeID = 2; nodeDescr = "Electrical"; parentID = Some(0) } ;
{ nodeID = 3; nodeDescr = "High Voltage"; parentID = Some(2) } ;
{ nodeID = 4; nodeDescr = "Low Voltage"; parentID = Some(2) } ;
{ nodeID = 5; nodeDescr = "HV Maintanence"; parentID = Some(3) } ;
{ nodeID = 6; nodeDescr = "City Power"; parentID = Some(3) } ;
{ nodeID = 7; nodeDescr = "LV Wiring"; parentID = Some(4) } ;
{ nodeID = 8; nodeDescr = "LV Maintanence"; parentID = Some(4) } ]
let getChildren (id : int) (tree : list<leaf>) =
let allChildren = new List<leaf>() // Mutable list
let rec getAllChildren (id : int) (t : list<leaf>) =
let cl = List.filter (fun x -> x.parentID = Some id) t // Get the immediate children
for c in cl do // Loop through the immediate children and recursively get their children
allChildren.Add(c)
getAllChildren c.nodeID t
getAllChildren id tree
allChildren
我在这里的担忧是:
我怀疑在F#中使用函数式编程时,有一种更优雅的方法来避免变异和循环,并且我的命令式编程习惯正在偷偷摸摸。
此外,这是建模树结构的好方法吗?请记住它需要从数据库表中存储和检索?
答案 0 :(得分:4)
如果你想保留你已经拥有的树结构,这个函数会为你找到孩子,没有循环或可变的值:
let getChildren (id : int) (tree : list<leaf>) =
let parent node = tree |> Seq.filter (fun x -> Some x.nodeID = node.parentID) |> Seq.exactlyOne
let rec hasAncestor (node : leaf) =
node.parentID = Some id || (node.parentID.IsSome && hasAncestor (parent node))
tree |> Seq.filter hasAncestor
但是你真正想要的是一个结构,其中每个节点存储对其子节点的引用,当你去序列化数据时,你可以从引用中找到ID
这样的事情应该足以让你指出正确的方向:
type Node = {
Id : int;
Description: string;
Children: seq<Node>
}
let myTree =
{ Id = 0; Description = "Root"; Children =
[
{ Id = 1; Description = "Mechanical"; Children = [] };
{ Id = 2; Description = "Electrical"; Children =
[
{ Id = 3; Description = "High Voltage"; Children =
[
{ Id = 5; Description = "HV Maintanence"; Children = [] };
{ Id = 6; Description = "City Power"; Children = [] }
] };
{ Id = 4; Description = "Low Voltage"; Children =
[
{ Id = 7; Description = "LV Wiring"; Children = [] } ;
{ Id = 8; Description = "LV Maintanence"; Children = [] }
] }
]};
]}
let rec getChildren (node : Node) =
Seq.concat [node.Children; (Seq.collect getChildren node.Children)]