Как получить часть молнии Clojure, уже посещенной при первом прохождении? - PullRequest
1 голос
/ 27 сентября 2019

Когда вы перебираете произвольно вложенную 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 возвращает только посещенную часть на том же иерархическом уровне.

Ответы [ 3 ]

1 голос
/ 28 сентября 2019

Ваше замечание о том, что "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)))))))
1 голос
/ 27 сентября 2019

не легко.Вы хотите в качестве выходного значения [0 [1 2]], но это значение никогда не посещалось.Таким образом, вы не можете получить его, просто взглянув на любой ранее посещенный узел.Вместо этого вам придется самостоятельно найти способ создания этой структуры на основе изучения истории посетителя.

Это не кажется невозможным, но алгоритм не совсем очевиден.Мое первое возражение состоит в том, что проблема, по-видимому, плохо определена: действительно ли вы хотите, чтобы «уже посещенный набор» равнялся shrink при посещении?Вы говорите, что при посещении [1 2] вы рассматриваете уже посещенную часть как [0 [1 2]], подразумевая, что, глядя на вектор [1 2], вы считаете, что все его содержимое уже посещено.В этом случае, когда вы смотрите на корень, все дерево уже посещено, и когда вы спускаетесь в него, оно становится все менее и менее посещаемым!

Так что я бы предложил сгладить более точное определениео том, что вы хотите, и, надеюсь, если вы будете достаточно строгими, алгоритм предложит себя.

0 голосов
/ 27 сентября 2019

Не прямой ответ с помощью Zippers, но вы можете легко решить эту проблему, используя Библиотека Tupelo Forest .Вот пример:

(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.

В зависимости от вашего конкретного случая использования вы можете при необходимости преобразовать формат вывода.

...