clojure - 如何获取已在深度优先遍历中访问过的 Clojure 拉链部分?
问题描述
当您以深度优先方式遍历任意嵌套的Clojure 拉链z/next
时,您能否获取或重建拉链已经访问过的部分,并保留其结构?例如,让我们有一个矢量拉链[0 [1 2] 3]
。如何实现一个函数visited
来返回拉链的访问部分,例如[0 [1]]
访问时1
?
编辑:在有用的答案的提示下,我意识到loc
只有当它的子树被完全遍历时,才可以考虑访问它。因此,只有非分支位置(即(complement z/branch?)
)才算作已访问。
(require '[clojure.zip :as z])
(def zipper (z/vector-zip [0 [1 2] 3]))
(defn visited
[zipper]
; ...
)
(-> zipper z/next visited)
; => [0]
(-> zipper z/next z/next visited)
; => [0]
(-> zipper z/next z/next z/next visited)
; => [0 [1]]
(-> zipper z/next z/next z/next z/next visited)
; => [0 [1 2]]
(-> zipper z/next z/next z/next z/next z/next visited)
; => [0 [1 2] 3]
z/lefts
仅返回同一层级上的已访问部分。
编辑 2:amalloy 的答案似乎几乎可行。如果我们让它以 开头into
,那么它对于示例拉链可以正常工作:
(def visited
(letfn [(root? [node]
(= (z/node node) (z/root node)))]
(fn [node]
(if-let [parent (z/up node)]
(let [comb-fn (if (root? parent) into conj)]
(comb-fn (visited parent)
(if (z/branch? node)
(vec (z/lefts node))
(conj (vec (z/lefts node)) (z/node node)))))
[])))) ;; we're at the root
然而,随着更多的嵌套,它的局限性变得明显。例如:
(def zipper (z/vector-zip [0 [1 [2]]]))
(-> zipper z/next z/next z/next z/next z/next visited)
; => [0 [1] [2]]
我想知道是否z/edit
可以更好地适应。
解决方案
不容易。您希望将 value 作为输出[0 [1 2]]
,但从未访问过该值。因此,您无法仅通过查看任何先前访问过的节点来获得它。相反,您必须根据访问者的历史找出一种方法来自己创建此结构。
这听起来并非不可能,但算法并不完全显而易见。我的第一个反对意见是这个问题似乎定义不清:你真的希望“已经访问过的集合”在你访问事物时缩小吗?你说在访问时[1 2]
你认为已经访问过的部分是[0 [1 2]]
,这意味着当你查看向量时,[1 2]
你认为它的所有内容都已经被访问过。在这种情况下,当您查看根时,整棵树已经被访问过,当您深入其中时,它会变得越来越少!
因此,我建议对您想要的内容进行更准确的定义,并希望如果您对此足够严格,算法会自行提出建议。
推荐阅读
- html - .css 文件中的外部样式表是否会覆盖以前的样式表?
- asp.net-core - 选择框中未显示 ASPNET Core 5.0:Visual Studio 2019 16.6
- corda - Corda - 机密身份与匿名功能
- php - 在 rest api 或 POST 上发送 fcm 通知
- javascript - 根据moodle表单中的更改选择元素选择日期范围并设置默认日期
- spring - 如何让补丁休息方法与 Feign 客户端一起工作
- sql - Oracle - 从时间戳字段中截断时间
- r - 从数据框中过滤数据的问题
- r - bookdown 项目:如何通过 circleci 强制执行代码格式化?
- javascript - 单元测试 ActivatedRoute queryParams 在销毁组件时取消订阅