2016-09-02 3 views
1

Я хочу использовать clojure.zip, чтобы пройти через это дерево и распечатать узел и его родителя. У меня возникли проблемы с получением родителя. Например, родительский элемент :e равен :b.Найти всех родителей, прогуливаясь по дереву

;; 
;;  :a 
;; /\ 
;; :b :c 
;; /\ \ 
;; :d :e :f 
;; 
(def example [:a [:b [:d] [:e]] [:c [:f]]]) 
(def z (zip/vector-zip example)) 
(def locs (take-while (complement zip/end?) (iterate zip/next z))) 

(defn parent-of [loc] 
    (when-let [parent-loc (-> loc zip/up zip/left)] 
    (zip/node parent-loc))) 

(defn visit-all [] 
    (doseq [loc locs] 
    (let [node (zip/node loc)] 
     (when (keyword? node) 
     (println node "has parent" (parent-of loc)))))) 

Это результат:

:a has parent nil 
:b has parent :a 
:d has parent :b 
:e has parent [:d] 
:c has parent [:b [:d] [:e]] 
:f has parent :c 

Я мог бы продолжать улучшать функцию parent-of - моя следующая мысль будет идти в самый левый узел. Там будет алгоритм, который вернет правильный ответ из всех мест - однако, по его мнению, это довольно много работы для общего требования.

Есть ли лучший подход, который я должен взять?

Редактировать Этот вопрос не о clojure.walk или Spector. Я ищу ответ, который использует clojure.zip и дает родителям, как я определил его в вопросе, который является просто ключевым словом выше loc. Поэтому, если loc, присвоенный parent-of, равно :f, я бы ожидал, что он вернется :c.

Если кто-то может сказать мне, как комментарий, то молнии на самом деле больше не используются, и говорят, что clojure.walk или Spector - это самая лучшая практика для навигации по деревьям, а затем это поможет.

+0

Можете ли вы предоставить примеры входы и выходы для функции, которую вы пытаетесь реализовать? – OlegTheCat

+0

Возможный дубликат [Clojure - walk with path] (http://stackoverflow.com/questions/33594375/clojure-walk-with-path) – nha

ответ

2

Почему вы используете zip/left? Родитель узла - это именно узел над ним, а не узел над ним и по какой-то причине слева. Удаление этого - все, что вам нужно сделать.

+0

Я понимаю, что технически говоря 'zip/up' дает родительский. Но родитель всегда будет просто охватывающим вектором. То, что мне нужно (я считаю), является первым элементом этого охватывающего вектора. Вот почему в моем вопросе я сказал, что родительский элемент ': e' is': b', хотя и с технической точки зрения родительский элемент ': e' is' [: b [: d] [: e]] '. –

+0

Итак, вызовите 'first' на результат' (z/loc (z/up loc)) ', если вы хотите только метку узла, а не его структуру. – amalloy

0

Это мой собственный ответ:

(defn parent-of [loc] 
    (when-let [parent-loc (-> loc zip/up zip/up first)] 
    (zip/node parent-loc))) 

Это дает правильный выход во всех случаях:

:a has parent nil 
:b has parent :a 
:d has parent :b 
:e has parent :b 
:c has parent :a 
:f has parent :c