如何使用 clojure 拉链获取只有叶子的树中所有子节点的路径?

2024-02-22

假设我有一棵这样的树。我想获取仅包含叶子而不包含非叶子子节点的子节点的路径。

那么对于这棵树

root
├──leaf123
├──level_a_node1
│   ├──leaf456
├──level_a_node2
│  ├──level_b_node1
│  │  └──leaf987
│  └──level_b_node2
│     └──level_c_node1
|        └── leaf654
├──leaf789
└──level_a_node3
   └──leaf432

结果将是

[["root"  "level_a_node1"]
["root"  "level_a_node2" "level_b_node1"]
["root"  "level_a_node2" "level_b_node2" "level_c_node1"]
["root"  "level_a_node3"]]

我试图深入到底部节点并检查是否(lefts)(rights)不是分支,但这不太有效。

(z/vector-zip ["root"
               ["level_a_node3" ["leaf432"]]
               ["level_a_node2" ["level_b_node2" ["level_c_node1" ["leaf654"]]] ["level_b_node1" ["leaf987"]] ["leaf789"]]
               ["level_a_node1" ["leaf456"]]
               ["leaf123"]])

编辑:我的数据实际上是作为路径列表输入的,我将其转换为树。但也许这过于复杂化了?

[["root" "leaf"]
["root"  "level_a_node1" "leaf"]
["root"  "level_a_node2" "leaf"]
["root"  "level_a_node2" "level_b_node1" "leaf"]
["root"  "level_a_node2" "level_b_node2" "level_c_node1" "leaf"]
["root"  "level_a_node3" "leaf"]]

打嗝式建筑是一个值得参观的好地方,但我不想住在那里。也就是说,它们写起来非常简洁,但以编程方式操作却非常痛苦,因为语义嵌套结构没有反映在节点的物理结构中。因此,我要做的第一件事就是转换为 Enlive 风格的树表示(或者,理想情况下,首先生成 Enlive):

(def hiccup
  ["root"
   ["level_a_node3" ["leaf432"]]
   ["level_a_node2"
    ["level_b_node2"
     ["level_c_node1"
      ["leaf654"]]]
    ["level_b_node1"
     ["leaf987"]]
    ["leaf789"]]
   ["level_a_node1"
    ["leaf456"]]
   ["leaf123"]])
(defn hiccup->enlive [x]
  (when (vector? x)
    {:tag (first x)
     :content (map hiccup->enlive (rest x))}))
(def enlive (hiccup->enlive hiccup))

;; Yielding...
{:tag "root",
 :content
 ({:tag "level_a_node3", :content ({:tag "leaf432", :content ()})}
  {:tag "level_a_node2",
   :content
   ({:tag "level_b_node2",
     :content
     ({:tag "level_c_node1",
       :content ({:tag "leaf654", :content ()})})}
    {:tag "level_b_node1", :content ({:tag "leaf987", :content ()})}
    {:tag "leaf789", :content ()})}
  {:tag "level_a_node1", :content ({:tag "leaf456", :content ()})}
  {:tag "leaf123", :content ()})}

完成此操作后,最后一个阻碍您的事情就是您对使用拉链的渴望。它们是有针对性的遍历的好工具,您非常关心正在处理的节点附近的结构。但如果您只关心节点及其子节点,那么只需编写一个简单的递归函数来遍历树就会容易得多:

(defn paths-to-leaves [{:keys [tag content] :as root}]
  (when (seq content)
    (if (every? #(empty? (:content %)) content)
      [(list tag)]
      (for [child content
            path (paths-to-leaves child)]
        (cons tag path)))))

像这样编写递归遍历的能力是一项在您的 Clojure 职业生涯中多次为您服务的技能(例如,我最近在代码审查中回答了一个类似的问题 https://codereview.stackexchange.com/q/219144/2993)。事实证明,树上的大量函数只是:在每个子节点上递归地调用自己,并以某种方式组合结果,通常是在可能嵌套的形式中for环形。困难的部分只是弄清楚您的基本情况需要是什么,以及正确的映射/映射猫序列来组合结果,而不会引入不需要的嵌套级别。

如果您坚持使用 Hiccup,您可以在使用现场将其拆解,而不会造成太大痛苦:

(defn hiccup-paths-to-leaves [node]
  (when (vector? node)
    (let [tag (first node), content (next node)]
      (if (and content (every? #(= 1 (count %)) content))
        [(list tag)]
        (for [child content
              path (hiccup-paths-to-leaves child)]
          (cons tag path))))))

但它明显更混乱,并且每次处理树时都必须重复这项工作。我再次鼓励您使用 Enlive 风格的树来表示内部数据。

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

如何使用 clojure 拉链获取只有叶子的树中所有子节点的路径? 的相关文章

  • 如何使用 core.async 在 Clojure 中写入日志文件?

    我想使用 core async 作为写入文件的记录器 因此我创建了一个 test txt 文件 将其粘贴在我的资源文件夹中并编写了以下代码 use clojure java io use clojure core async def pri
  • Tic-Tac-Toe AI:如何制作树?

    在制作井字游戏机器人时 我在尝试理解 树 时遇到了巨大的障碍 我理解这个概念 但我不知道如何实现它们 有人可以向我展示一个如何为这种情况生成树的示例吗 或者关于生成树的好教程 我想最困难的部分是生成部分树 我知道如何实现生成整棵树 但不知道
  • 什么时候应该在 Clojure 中使用临时重新绑定特殊变量这一习惯用法?

    我注意到一些库 例如 clojure twitter 使用特殊的变量 用于动态绑定的变量 被星号包围 进行 oauth 身份验证 您将身份验证保存在 var 中 然后使用 with oauth myauth 我认为这是解决此类问题的一个非常
  • 好的 Clojure 代码示例? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在第一次查看 Clojure 我发现查看 Clojure 核心库的 doc xxx 和 sourc
  • 从 JVM 线程本地空间卸载 Clojure 变量

    我正在 Clojure 中为 BaseX 编写一个插件 通过 lein uberjar 构建 并包含 Clojure 解释器 在大多数情况下 这效果很好 然而 当通过 BaseX HTTP 实例运行时 评估在 Jetty 的线程池内进行 而
  • 如何按层次结构对文件路径名进行排序?

    我想按层次结构对文件名进行排序 假设我有以下文件夹列表 D Movies Hollywood Comedy adultcomedy D Movies Hollywood Comedy horrorcomedy D Movies Hollyw
  • 知识树中的段错误

    我正在用 c 实现一个可以从文件中读取的知识树 我的 newStr 函数出现段错误 我无法用这个问题测试我的其余代码 我对 c 没有太多经验 任何帮助将不胜感激 我的 c 文件 包括 包括 include 动物 h 包括 包括 return
  • 我从 clojure 和 python 中得到的 hmac 签名略有不同

    我从 python 实现和 clojure 实现中获得的 HMAC SHA1 签名略有不同 我很困惑什么会导致这种情况 Python实现 import hashlib import hmac print hmac new my key my
  • 这两个 clojure 函数之间有什么区别和问题?

    对于课程项目的一部分 我正在实现一个函数来从文件中读取一些数据并根据该文件创建图形结构 一整天我问了几个问题 结果就是这样 下面是一个可以正常工作的函数 它首先以惰性序列的形式读入文件 然后循环解析每一行并将其打印出来 defn print
  • 如何修复 STL 样式容器以容纳不完整或抽象类型?

    几天前 我尝试以与 STL 容器相同的风格编写一个基本的树实现 现在我尝试在我的代码中使用它 但是有两件事似乎不起作用 但可以说std vector 即 使用不完整类型和使用抽象类型 如何修复我的树实现以获得此功能 我尝试稍微压缩一下我的代
  • 枚举和 Clojure

    在Java C世界中 人们经常使用枚举 如果我使用的是使用枚举的 Java 库 我可以在它们和关键字之间进行转换 例如 使用 java lang Enum valueOf e aget Ljava lang Enum e getEnumCo
  • 非二叉树的中序树遍历

    对于比二叉树更宽的树 术语 中序遍历 是否有明确定义的含义 或者 前 和 后 顺序是唯一有意义的 DFS 类型吗 我的意思是与n每个节点 gt 2 个子节点 我猜是为了n这甚至可能意味着之后要转到 根 n 2孩子们 但这曾经这样使用过吗 那
  • Clojure:让作用域和函数返回值

    我在弄清楚如何使用 let 形式时遇到了一些麻烦 在下面的示例中 我想在本地绑定值 cols 以便稍后在函数中处理它 然而 我注意到 如果我使用 let 函数 sel opt tmp 将返回 nil 值而不是列表 defn sel opt
  • Clojure:只能从尾部位置重复

    我正在尝试递归地反转列表 但是我得到了Can only recur from tail position运行时 这到底意味着什么 如何改进我的代码才能使其正常工作 defn recursive reverse coll loop coll
  • 使用 Java 进行树可视化 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个库来生成图形或树 例如组织图表 该库应该能够从该图中生成纯图像 有谁知道一个好的 希望开源
  • 使用 Compojure、Hiccup 和 Ring 上传文件

    要将文件上传到我用 Clojure 编写的服务器 我需要一个如下所示的客户端表单
  • d3.js:修改树布局中的链接

    抱歉我的英语不好 我在这里使用这个例子 http bl ocks org mbostock 4339083 http bl ocks org mbostock 4339083构建树形图 但我用矩形更改了根的子级中的圆圈 现在该图有点混乱 因
  • Clojure/Ring:使用环码头适配器,大请求会给我一个 413: FULL HEAD 错误。

    使用 Ring 的 Jetty 适配器 如果我的请求太大 我会收到 413 FULL HEAD 错误 我追踪到一个名为 headerbuffersize 的属性 但是当我尝试在 run jetty 调用中设置它时 我仍然得到 413 有没有
  • 应用对数来导航树

    我曾经知道一种使用对数从树的一片叶子移动到树的下一个 有序 叶子的方法 我认为它涉及获取 当前 叶子的位置值 排名 并将其用作从根向下到新目标叶子的新遍历的种子 一直使用对数函数测试来确定是否沿着右或左节点向下到达叶子 我已经不记得如何运用
  • 在 clojure 中,使用递归实现宏时如何进行代码模板化

    我正在尝试实现一个宏 以递归地将中缀列表转换为前缀列表 我遇到一个问题如下 this works defmacro recursive infix form list second form first form if not seq nt

随机推荐