使用F#在树中寻找孩子

时间:2013-09-01 15:22:18

标签: .net f# tree

我正在尝试使用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

我在这里的担忧是:

  1. 我正在使用一个可变列表
  2. 我正在使用循环
  3. 我怀疑在F#中使用函数式编程时,有一种更优雅的方法来避免变异和循环,并且我的命令式编程习惯正在偷偷摸摸。

    此外,这是建模树结构的好方法吗?请记住它需要从数据库表中存储和检索?

1 个答案:

答案 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)]