F# 将列表转换为树

2024-03-10

我有一个元组 int*string 列表,其中 int 是级别,string 是名称

let src = [
        (0, "root");
            (1, "a");
                (2, "a1");
                (2, "a2");
            (1, "b");
                (2, "b1");
                    (3, "b11");
                (2, "b2");
        ]

我需要将其转换为以下内容

let expectingTree = 
    Branch("root", 
    [
        Branch("a",
            [
                Leaf("a1");
                Leaf("a2")
            ]);
        Branch("b",
            [
                Branch("b1", [Leaf("b11")]);
                Leaf("b2")
            ]);
    ]);

以下是我的做法,但任何人都可以建议更好的方法来实现这一目标。 我是 F# 新手,执行相同操作的 C# 代码会更短,所以我想我做错了。

type Node = 
    | Branch of (string * Node list)
    | Leaf of string

let src = [
            (0, "root");
                (1, "a");
                    (2, "a1");
                    (2, "a2");
                (1, "b");
                    (2, "b1");
                        (3, "b11");
                    (2, "b2");
            ]

let rec setParents (level:int) (parents:list<int>) (lst:list<int*int*string>) : list<int*int*string> =
    //skip n items and return the rest
    let rec skip n xs = 
        match (n, xs) with
        | n, _ when n <= 0 -> xs
        | _, [] -> []
        | n, _::xs -> skip (n-1) xs

    //get parent id for given level
    let parentId (level) = 
        let n = List.length parents - (level + 1)
        skip n parents |> List.head 

    //create new parent list and append new id to begin
    let newParents level id =
        let n = List.length parents - (level + 1)
        id :: skip n parents

    match lst with
    | (id, l, n) :: tail -> 
                        if l = level then (id, parentId(l), n) :: setParents l (newParents l id) tail
                        elif l <= level + 1 then setParents l parents lst
                        else [] //items should be in order, e.g. there shouldnt be item with level 5 after item with level 3
    | _ -> []


let rec getTree (root:int) (lst: list<int*int*string>) =

    let getChildren parent = 
        List.filter (fun (_, p, _) -> p = parent) lst

    let rec getTreeNode (id:int) (name:string) =
        let children = getChildren id
        match List.length children with
        | 0 -> Leaf(name)
        | _ -> Branch(name, 
                        children
                        |> List.map (fun (_id, _, _name) -> getTreeNode _id _name))

    match getChildren root with
    | (id, _, n) :: _ -> getTreeNode id n
    | _ -> Leaf("")

let rec printTree (ident:string) (tree:Node) = 
    match tree with
    | Leaf(name) -> 
        printfn "%s%s" ident name
    | Branch(name, children) -> 
        printfn "%s%s" ident name
        List.iter (fun (node) -> printTree ("   " + ident) node) children

let tree = 
    src
    |> List.mapi (fun i (l, n) -> (i+1, l, n)) //set unique id to each item
    |> setParents 0 [0] //set parentId to each item
    |> getTree 0


printTree "" tree

Console.ReadKey() |> ignore

首先,你并不需要有一个杰出的案例Leaf如果您的分支包含子树列表,因为叶子只是一个没有子树的分支。因此,我将使用以下树类型:

type Tree = 
  | Branch of string * list<Tree>

使用显式递归列表处理可能更容易实现将列表转换为树的核心功能。您可以一次性完成此操作 - 只需遍历元素并在找到嵌套索引时启动一个新分支(或者当您获得较小的索引时从适当数量的递归调用中返回)。这是我的尝试:

/// Build a tree from elements of 'list' that have larger index than 'offset'. As soon
/// as it finds element below or equal to 'offset', it returns trees found so far
/// together with unprocessed elements.
let rec buildTree offset trees list = 
  match list with
  | [] -> trees, [] // No more elements, return trees collected so far
  | (x, _)::xs when x <= offset -> 
      trees, list // The node is below the offset, so we return unprocessed elements
  | (x, n)::xs ->
      /// Collect all subtrees from 'xs' that have index larger than 'x'
      /// (repeatedly call 'buildTree' to find all of them)
      let rec collectSubTrees xs trees = 
        match buildTree x [] xs with
        | [], rest -> trees, rest
        | newtrees, rest -> collectSubTrees rest (trees @ newtrees)
      let sub, rest = collectSubTrees xs []
      [Branch(n, sub)], rest

该函数采用初始偏移量和迄今为止收集的树木。这trees参数总是[]并且您需要一些初始值offset。结果是给定级别以下的树列表和剩余元素的列表:

let res = buildTrees -1 [] src

假设 root 高于 -1,您可以忽略元组的第二部分(它应该是空列表)并获取第一棵树(应该只有一棵):

/// A helper that nicely prints a tree
let rec print depth (Branch(n, sub)) =
  printfn "%s%s" depth n
  for s in sub do print (depth + "  ") s

res |> fst |> Seq.head |> print ""
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

F# 将列表转换为树 的相关文章

  • 如何用约束标记一大组“传递群”?

    在 NealB解决方案之后进行编辑 与以下解决方案相比 NealB的解决方案非常非常快任何另一个 https stackoverflow com q 18033115 answers and 提出了关于 添加约束以提高性能 的新问题 Nea
  • 每个术语出现的次数

    我得到了一个数组a n 2 where n can be 10 5最大时有n个科目和n个学生 全部编号为 1 2 n a i 0 and a i 1 1 lt i lt n 表示在第 i 个科目中 所有来自a i 0 to a i 1 通过
  • 需要使用 pyparsing 制作递归解析器的帮助

    我正在尝试使用 python pyparsing 进行解析 我在制作递归解析器时陷入困境 让我解释一下问题 我想要计算元素的笛卡尔积 语法是 cross elements element 我用更具体的方式 cross a c1 or cro
  • 数学/算法使图像适合屏幕保留纵横比

    我需要数学 算法方面的帮助来拍摄已知尺寸的图像并适合两个屏幕尺寸之一 720 x 480 或 1280 x 1024 图像尺寸来自 XML 文件 但这些尺寸是 Web 尺寸 我还从 XML 中选择了一些图像 这些图像的分辨率可能比 Web
  • 递归修剪对象中所有元素的更好方法?

    如果我有一个像这样的物体 const obj field subfield innerObj a asdasd asdas innerArr s ssad innerArrObj b adsad 我想出了这样的东西 const trimFi
  • O(1) 算法确定节点是否是多路树中另一个节点的后代?

    想象一下下面的树 A B C D E F 我正在寻找一种方法来查询 F 是否是 A 的后代 注意 F 不需要是directA 的后代 在这种特殊情况下这是正确的 只需要针对更大的潜在后代节点池测试有限数量的潜在父节点 当测试一个节点是否是潜
  • 动态规划 (DP) 中的重叠子问题是什么?

    为了使动态规划适用 问题必须具有两个关键属性 最优子结构 and 重叠子问题 1 https en wikipedia org wiki Dynamic programming 对于这个问题 我们只关注后一个属性 有各种不同的定义重叠子问题
  • 合并xml文档

    我遇到的所有关于合并 XML 文档的解决方案都无法实现我的愿望 让我解释 XML 文档 1 a b title Original Section b title Original Child Section b b title Origin
  • Python如何处理无限递归?

    因此 在使用 Python 时 我注意到程序的堆栈大小基本上没有限制 继续对数字执行幂运算 即使在达到数千位之后 精度仍然保持完美 这让我想知道 如果我不小心进入了Python的无限递归循环怎么办 编译器会注意到并抛出堆栈溢出错误吗 或者程
  • 来自 JSON 的 Angular 8 动态表单

    我正在尝试从 JSON 模式递归生成动态表单 但我正在努力解决找不到表单控件的问题 这是代码示例 我收到这个错误 错误错误 找不到名称为 createdAt 的控件 我尝试了不同的方法 但仍然存在问题 我知道我错过了一些东西 所以请帮忙 任
  • PHP递归遍历对象树[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • AStar-名称解释

    我正在寻找 AStar A 算法为何被称为 AStar 的解释 所有类似的 最短路径问题 算法通常都以其开发者的名字命名 那么 AStar 代表什么 有称为 A1 和 A2 的算法 后来证明A2是最优的 实际上也是可能的最好算法 所以他给它
  • 使用到达时间差对信号进行三边测量

    我在寻找或实现寻找信号源的算法时遇到一些麻烦 我的工作目标是找到声音发射器的位置 为了实现这一点 我使用了三个麦克风 我正在使用的技术是多点定位这是基于到达时间差 The 到达时间差使用发现每个麦克风之间互相关接收到的信号 我已经实现了算法
  • 如何编写一个计算表达式生成器来累积值并允许标准语言构造?

    我有一个计算表达式生成器 可以随时生成值 并且有许多自定义操作 但是 它不允许标准 F 语言构造 并且我在弄清楚如何添加此支持方面遇到了很多麻烦 举一个独立的例子 下面是一个非常简单且毫无意义的构建 F 列表的计算表达式 type Item
  • 依赖解析算法

    我正在编写一个包管理器 为此我希望依赖项解析尽可能强大 每个包都有一个版本列表 每个版本包含以下信息 具有可比性的 ID 依赖关系 软件包列表以及每个软件包的一组可接受的版本 冲突 软件包列表以及每个软件包的一组与该版本一起导致问题的版本
  • php递归合并

    我需要以某种不同的方式合并一些数组 我使用 array merge recursive 然而 有一些事情我需要改变 但我不知道如何改变 这是来自 php net 的引用 但是 如果数组具有相同的数字键 则后面的值 不会覆盖原始值 但会追加
  • 并行化斐波那契序列生成器

    我正在学习并行化 在一项练习中 我得到了一些我应该提高性能的算法 其中之一是斐波那契数列生成器 array 0 0 array 1 1 for q 2 q lt MAX q array q array q 1 array q 2 我怀疑 这
  • 如何从 Trie 中检索给定长度的随机单词

    我有一个简单的 Trie 用来存储大约 80k 长度为 2 15 的单词 它非常适合检查字符串是否是单词 但是 现在我需要一种获取给定长度的随机单词的方法 换句话说 我需要 getRandomWord 5 来返回 5 个字母的单词 所有 5
  • 贪心技术与穷举搜索有何不同?

    我正在为一些示例问题编写伪代码 并且我注意到贪婪技术和详尽搜索之间存在令人担忧的模式 Job 1 Job 2 Job 3 Job 4 Job 5 Person 1 9 2 7 8 Person 2 6 4 3 7 Person 3 5 8
  • 如何高效生成总和在指定范围内的所有组合(在所有深度)

    假设您有一组值 1 1 1 12 12 16 如何生成总和在预定义范围内的所有可能组合 不重复 min max 例如 这里是 所有深度的 范围在13 and 17 1 12 1 1 12 1 1 1 12 16 1 16 这假设具有相同值的

随机推荐

  • 使用 Mockito 检查多个参数的一致性

    我正在使用 Mockito 来模拟一个类 该类的方法如下所示 setFoo int offset float floats 我希望能够验证数组中的值 floats 等于 在给定容差范围内 预期值数组中的值 问题是我想检查的内容floats从
  • 如何对 Matlab 语言进行写保护?

    Matlab 允许您覆盖内置函数而无需发出警告 例如 我重写了该函数max 有一个变量 但 Matlab 没有提醒我这一点 仅在稍后调用该函数时才会抛出错误 并且不能帮助您查看实际问题 min 0 max 10 x linspace min
  • 表示 DAG(有向无环图)

    我需要将依赖项存储在 DAG 中 我们正在非常细粒度地 制定新的学校课程 我们使用的是 Rails 3 注意事项 宽大于深 很大 我估计每个节点有 5 10 个链接 随着系统的增长 这个值将会增加 读多写少 most common are
  • 如何在 XNA 中暂停重绘?

    我制作了一个 XNA 图像查看器 但它总是重新绘制场景 即使它没有改变 而且它让我的上网本烧得很厉害 所以我希望它在没有任何变化时暂停绘制 将帧速率降低到 1 是保持凉爽的一种方法 但会导致输出滞后 如何在没有输入的情况下防止重绘 这个问题
  • 如何更改 JFreeChart 的大小

    我添加了一个JFreeChart to a JPanel 用一个BorderLayout 并且它是huge 我可以做些什么来让它变小吗 public void generateChart DefaultCategoryDataset dat
  • 这个Handler类应该是静态的,否则可能会发生泄漏:AsyncQueryHandler

    处理程序引用泄漏 由于此处理程序被声明为内部类 因此可能会阻止外部类被垃圾收集 如果 Handler 在主线程以外的线程中使用 Looper 或 MessageQueue 则没有问题 如果 Handler 使用主线程的 Looper 或 M
  • 如何对具有多个值的多个列求和

    我正在寻找以下问题的解决方案 进入用户表并查找在网站上列出了项目的用户 在这个用户表中 没有关于拍卖的列 相反 它通过键连接到帐户表 在帐户中 此列称为用户 从这些 ID 已列出拍卖物品的用户 中 我需要找到他们的帐户余额 这也在账户表中
  • 将 jdouble 转换为 c 类型的 double

    我怎样才能转换jdoublejava类型变量为doublec 类型的变量 你不必这样做 它只是一个 typedef 如下所示 typedef double jdouble 所以一旦你有了一个 就不需要转换jdouble你可以把它当作doub
  • 是否使用drawRect(什么时候应该使用drawRect/Core Graphics vs 子视图/图像,为什么?)

    为了澄清这个问题的目的 我知道如何使用子视图和使用drawRect创建复杂的视图 我试图完全理解何时以及为何使用其中一种而不是另一种 我也明白提前优化那么多并在进行任何分析之前以更困难的方式做一些事情是没有意义的 考虑到我对这两种方法都很满
  • 为什么CSS3中有-moz-XXX和-webkit-XXX?

    我在 CSS3 中最讨厌的一点是 你总是应该使用两个属性来实现一种效果 我觉得这样不专业 加大CSS大小 例如 他们为什么不团结起来 webkit border radius and moz border radius in border
  • ValueTypes 如何从 Object (ReferenceType) 派生并且仍然是 ValueTypes?

    C 不允许从类派生结构 但所有 ValueType 都从 Object 派生 这种区别是在哪里做出的呢 CLR 如何处理这个问题 C 不允许从类派生结构 你的说法不正确 因此你感到困惑 C does允许结构从类派生 所有结构都派生自同一个类
  • VS 2015中的类库(包)在哪里?

    我正在尝试将类库 包 添加到我的 ASP NET MVC 5 项目中 但由于某种原因我找不到该选项 我是否必须安装其他依赖项才能获得该选项 它现在称为 类库 NET Core
  • 重命名文件源

    我一直在从平面文件源开发 SSIS 包 该文件每天都会出现 文件名具有日期时间指示 如下所示 文件名 20190509042908 txt 我想知道如何才能度过约会部分 我希望包动态读取文件 但它应该在没有最后 6 位数字的情况下通过 我只
  • 使用 MinGW-w64 编译 32 位架构

    我已经安装了 MinGW w64 来编译为 64 位 但看来我必须安装两个单独版本的 MinGW w64 才能获得对 32 位的支持 我尝试过 使用批处理文件和 powershell 脚本等等 但最终效果不是很好 似乎有 multilib
  • Gradle 构建中 dexOptions 中 jumboMode 的用途是什么?

    根据这个帖子 https stackoverflow com a 24224385 1176435它允许 dex 文件中包含更多数量的字符串 但我不太明白它的含义以及对构建的影响 Jumbo 模式与可以引用的字符串数量有关 一个 DEX 文
  • 从 IndexedSeq[DataFrame] 转换为 DataFrame?

    新手问题 我尝试向现有 DataFrame 添加列 我正在使用 Spark 1 4 1 import sqlContext implicits case class Test rule Int val test sc parallelize
  • 从数据框中删除特殊字符和字母数字的简单方法

    我有一个大型数据集 其中有 x 行和 y 列 其中一列为单词和一些不需要的数据 不需要的数据没有特定的模式 因此我发现很难将其从数据框中删除 nonhashtag want better than Dhabi United Arab Emi
  • Cassandra 使用 IN 运算符在聚类列中更新和删除

    这是我的桌子 CREATE TABLE quorum omg id int a int b text c text PRIMARY KEY id a b WITH CLUSTERING ORDER BY b DESC 当我使用 IN 运算符
  • 为什么使用 OR 条件而不是 Union 会导致性能问题

    您好 我在 SP 中有以下查询 CrmContactId 是 SP 的参数 Select distinct A PolicyBusinessId A PolicyDetailId from TPolicyBusiness A inner j
  • F# 将列表转换为树

    我有一个元组 int string 列表 其中 int 是级别 string 是名称 let src 0 root 1 a 2 a1 2 a2 1 b 2 b1 3 b11 2 b2 我需要将其转换为以下内容 let expectingTr