【问题标题】:Finding children in a tree using F#使用 F# 在树中查找孩子
【发布时间】:2013-09-02 00:32:32
【问题描述】:

我正在尝试使用 F# 对简单的树结构进行建模,并且不禁认为我做得很糟糕:

我的树本质上是一个叶子列表(最终将被持久化到数据库表中)。我有一个 getChildren 函数,它接收叶节点 ID 并递归返回该叶的所有子节点。

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# 中使用函数式编程时有一种更优雅的方法可以避免突变和循环,而且我的命令式编程习惯正在潜移默化。

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

【问题讨论】:

    标签: .net f# tree


    【解决方案1】:

    如果你想保留你已经拥有的树结构,这个函数会为你找到孩子,没有循环或可变值:

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

    【讨论】:

    • 谢谢。我真的很喜欢你的 getChildren 实现。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-11
    • 2010-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多