Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何让Clojure拉链的一部分在深度优先遍历中已经访问过?_Clojure_Zipper - Fatal编程技术网

如何让Clojure拉链的一部分在深度优先遍历中已经访问过?

如何让Clojure拉链的一部分在深度优先遍历中已经访问过?,clojure,zipper,Clojure,Zipper,当您通过z/next以深度优先的方式迭代任意嵌套的拉链时,您能否获得或重建拉链的已访问部分,从而保留其结构?例如,让我们有一个向量拉链[0[12]3]。在访问1时,我如何实现visted功能以返回拉链的已访问部分,例如[0[1]] 编辑:在这些有用的答案的提示下,我意识到只有当它的子树被完全遍历时,loc才能被视为已访问。因此,只有非分支LOC(即(补码z/分支?)被视为已访问 (需要“[clojure.zip:as z]” (def拉链(z/vector拉链[0[12]3])) (defn访问

当您通过
z/next
以深度优先的方式迭代任意嵌套的拉链时,您能否获得或重建拉链的已访问部分,从而保留其结构?例如,让我们有一个向量拉链
[0[12]3]
。在访问
1
时,我如何实现
visted
功能以返回拉链的已访问部分,例如
[0[1]]

编辑:在这些有用的答案的提示下,我意识到只有当它的子树被完全遍历时,
loc
才能被视为已访问。因此,只有非分支LOC(即
(补码z/分支?
)被视为已访问

(需要“[clojure.zip:as z]”
(def拉链(z/vector拉链[0[12]3]))
(defn访问
[拉链]
; ...
)
(->拉链z/下次访问)
; => [0]
(->拉链z/下一个z/下一次访问)
; => [0]
(->拉链z/下一个z/下一个z/下一次访问)
; => [0 [1]]
(->拉链z/下一个z/下一个z/下一个z/下一个已访问)
; => [0 [1 2]]
(->拉链z/下一个z/下一个z/下一个z/下一个z/下一个已访问)
; => [0 [1 2] 3]
z/lefts
只返回同一层次上访问的零件

编辑2:这似乎几乎奏效了。如果我们将其从
开始改为
,则它对示例拉链正确工作:

(已访问def)
(letfn[(根?[节点]
(=(z/节点)(z/根节点))]
(fn[节点]
(如果让[父节点(z/up节点)]
(让[comb fn(如果(根?父)为conj)]
(梳fn(访问过的家长)
(如果(z/分支?节点)
(矢量控制(z/lefts节点))
(conj(vec(z/lefts节点))(z/node节点()()()))
[])))) ;; 我们是根源
然而,随着嵌套的增加,它的局限性变得越来越明显。例如:

(定义拉链(z/vector-zip[0[1[2]]))
(->拉链z/下一个z/下一个z/下一个z/下一个z/下一个已访问)
; => [0 [1] [2]]

我想知道
z/edit
是否更适合。

不容易。您希望将值
[0[1 2]]
作为输出,但从未访问过该值。因此,您不能仅仅通过查看以前访问过的任何节点来获得它。相反,您必须在检查访问者的历史记录的基础上,找到自己创建此结构的方法

这听起来不是不可能的,但算法并不完全显而易见。我的第一个反对意见是,这个问题似乎定义不清:您真的希望“已访问集”在访问时缩小吗?你说当访问<代码> [ 1 2 ] < /代码>时,你认为已经访问的部分是“代码> [0(1 2)] < /代码>,这意味着,当你查看矢量<代码> [1 2 ] < /代码>时,你认为它的所有内容都已经被访问过。在这种情况下,当您查看树根时,整个树已经被访问了,当您下降到树中时,访问量会越来越少


因此,我建议你对你想要的东西做出更准确的定义,如果你对它足够严格,我希望你能提出一个算法。

使用拉链不是一个直接的答案,但你可以很容易地解决这个问题。以下是一个例子:

(dotest-focus ; walk the tree and keep track of all the visited nodes
  (hid-count-reset)
  (with-forest (new-forest)
    ; an "hid" is like a pointer to the node
    (let [root-hid (add-tree-hiccup [:a
                                     [:b
                                      [:c 1]]
                                     [:d
                                      [:e 2]]])
          tgt-hid  (find-hid root-hid [:** :c]) ; hid of the :c node we want to stop at
          state-atom    (atom {:visited-hids []
                          :found-tgt?   false})
          enter-fn (fn [path] ; path is from root
                     (let [curr-hid (xlast path)] ; curr node is last elem in path
                       (swap! state-atom
                         (fn [curr-state]
                           (cond-it-> curr-state
                             (falsey? (grab :found-tgt? it)) (update it :visited-hids append curr-hid)
                             (= curr-hid tgt-hid) (assoc it :found-tgt? true))))))]
      (newline)
      (println "Overall Tree Structure:")
      (spy-pretty (hid->tree root-hid))
      (newline)
      (walk-tree root-hid {:enter enter-fn}) ; accum results => state atom
      (newline)
      (println "final state map")
      (spyx @state-atom)
      (newline)
      (let [depth-first-tags (it-> (grab :visited-hids @state-atom)
                               (mapv hid->node it)
                               (mapv #(grab :tag %) it))]
        (is= depth-first-tags [:a :b :c])
        (println "depth-first tags thru target:")
        (println depth-first-tags)
        (newline)))))
输出:

Overall Tree Structure:
{:tag :a,
 :tupelo.forest/kids
 [{:tag :b,
   :tupelo.forest/kids [{:tupelo.forest/kids [], :tag :c, :value 1}]}
  {:tag :d,
   :tupelo.forest/kids [{:tupelo.forest/kids [], :tag :e, :value 2}]}]}


final state map
(clojure.core/deref state) => {:visited-hids [1005 1002 1001], :found-tgt? true}

depth-first tags thru target:
[:a :b :c]

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.
根据您的具体用例,您可以根据需要调整输出格式。

您的评论“z/lefts只返回相同层次级别上访问的部分”表明了它自己的解决方案。调用z/lefts,然后使用z/up提升一个级别,然后递归地继续

我画了一个不完全正确的草图,但接近正确的形状,并说明了我的建议:

(defn visited [node]
        (let [parent (z/up node)]
          (if (nil? parent)
            [] ;; we're at the root
            (conj (visited parent) 
                  (if (z/branch? node)
                     (vec (z/lefts node))
                     (conj (vec (z/lefts node)) (z/node node)))))))

如果我正确理解你的目标,我相信这会奏效:

(defn visited [loc]
  (loop [cur loc
         start true]
    ;; Loop from the starting location up to the root
    (if-let [par (z/up cur)]
      (recur
        ;; Replace our parent with a node that only includes its visited children
        (z/replace
          par
          (z/make-node
            par
            (z/node par)
            (cond-> (z/lefts cur)
              ;; If we started at a branch, don't treat its children as visited
              (not (and start (z/branch? cur))) (concat [(z/node cur)]))))
        false)
      (if (and start (not (z/end? cur)))
        []
        (z/node cur)))))
作为测试,下面是一个示例,用于为相对复杂树的遍历中的每个步骤打印来自访问的
的返回:

(def root (z/vector-zip [[1 [2 3 4] 5] 6 [[[7 8] [9]] 10 11]]))
(loop [loc root]
  (when (not (z/end? loc))
    (println "visit " (z/node loc))
    (println "visited " (visited loc))
    (recur (z/next loc))))

visit  [[1 [2 3 4] 5] 6 [[[7 8] [9]] 10 11]]
visited  []
visit  [1 [2 3 4] 5]
visited  []
visit  1
visited  [[1]]
visit  [2 3 4]
visited  [[1]]
visit  2
visited  [[1 [2]]]
visit  3
visited  [[1 [2 3]]]
visit  4
visited  [[1 [2 3 4]]]
visit  5
visited  [[1 [2 3 4] 5]]
visit  6
visited  [[1 [2 3 4] 5] 6]
visit  [[[7 8] [9]] 10 11]
visited  [[1 [2 3 4] 5] 6]
visit  [[7 8] [9]]
visited  [[1 [2 3 4] 5] 6 []]
visit  [7 8]
visited  [[1 [2 3 4] 5] 6 [[]]]
visit  7
visited  [[1 [2 3 4] 5] 6 [[[7]]]]
visit  8
visited  [[1 [2 3 4] 5] 6 [[[7 8]]]]
visit  [9]
visited  [[1 [2 3 4] 5] 6 [[[7 8]]]]
visit  9
visited  [[1 [2 3 4] 5] 6 [[[7 8] [9]]]]
visit  10
visited  [[1 [2 3 4] 5] 6 [[[7 8] [9]] 10]]
visit  11
visited  [[1 [2 3 4] 5] 6 [[[7 8] [9]] 10 11]]
nil

谢谢你抓住了我问题的拙劣表述!事实上,我想要的是只为非分支LOC获取访问的部分。我不认为一个分支可以被视为被访问,除非它的子树被完全遍历。如果我读对了,它不会保留被访问树的结构。有几种方法可以用来输出被截断的树。你能描述一下这个问题的动机吗?例如,它可以用来显示网页的一部分(即Hiccup),直到给定的点。这几乎是有效的。如果我们以
开始,改为
而不是
conj
(参见上面我编辑的问题),它将正确地遍历示例拉链。但是,如果使用更多嵌套的数据结构,则会失败。