specter

Aviv 2025-09-18T07:02:05.097289Z

Hey everyone, I’m trying to traverse some nested tree in a level-order traversal, for example:

(defn descendants [cont]
    [(sp/recursive-path [] p
                        (sp/if-path  :children
                                     [:children sp/MAP-VALS (sp/stay-then-continue p)])) cont])
  

  (sp/select [(descendants [(sp/pred #(= (-> % :meta :name) "child1"))])]
             {:meta {:id "root" :name "root"}
              :children {:child1 {:meta {:id :child1 :name "child1"}
                                  :children {:child11 {:meta {:id :child11 :name "child11"}}}}
                         :child2 {:meta {:id :child2  :name "child2"}
                                  :children {:child1 {:meta {:id :child21 :name "child1"}}}}}})
  ;; Returns:
  ;; [{:meta {:id :child1, :name "child1"}, :children {:child11 {:meta {:id :child11, :name "child11"}}}}
  ;;  {:meta {:id :child21, :name "child1"}}]

  (sp/select [(descendants [(sp/pred #(= (-> % :meta :name) "child1"))])]
             {:meta {:id "root" :name "root"}
              :children {:child2 {:meta {:id :child2  :name "child2"}
                                  :children {:child1 {:meta {:id :child21 :name "child1"}}}}
                         :child1 {:meta {:id :child1 :name "child1"}
                                  :children {:child11 {:meta {:id :child11 :name "child11"}}}}}}))
;; Returns:
;; [{:meta {:id :child21, :name "child1"}}
;;  {:meta {:id :child1, :name "child1"}, :children {:child11 {:meta {:id :child11, :name "child11"}}}}]
In my specific case i want to get the descendants that satisfy some condition, but when selecting first - get the first based on level-order (so in both examples, first would be {:id "child1"} Any idea how can i achieve that?

nathanmarz 2025-09-18T15:48:44.724509Z

you can't traverse in level-order with Specter

Aviv 2025-09-28T13:36:02.541209Z

Thanks šŸ™

nathanmarz 2025-09-18T15:48:54.803759Z

but your path is simpler like this: (def DESCENDANTS (recursive-path [] p (continue-then-stay :children MAP-VALS)))

nathanmarz 2025-09-18T15:49:11.096199Z

and then you can use it like (select [DESCENDANTS (selected? :meta :name (pred= "child1"))] data)

xificurC 2025-09-18T18:41:45.854769Z

one could probably capture the depth during traversal and post-process with a sort