繁体   English   中英

使用F#在树中寻找孩子

[英]Finding children in a tree using F#

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

我怀疑在F#中使用函数式编程时,可以采用更优雅的方法来避免突变和循环,而我的命令式编程习惯正在悄悄溜走。

另外,考虑到需要从数据库表中存储和检索树结构,这是对树结构进行建模的好方法吗?

如果要保留已有的树结构,此函数将为您找到子级,而不会循环或产生可变值:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM