Hello, I have this data:
[{:id 0}
{:id 1}
{:id 2 :parent-id 1 :val 1}
{:id 3 :parent-id 1 :val 1}
{:id 4 :parent-id 2 :val 2}
{:id 5 :parent-id 3 :val 2}
{:id 6 :parent-id 3 :val 2}
{:id 7 :parent-id 0 :val 100}
{:id 8 :parent-id 7 :val 200}
{:id 9 :parent-id 6 :val 3}]
And I would like to traverse all the :val for :id = 1 and all its descendants. Is it possible with specter?@pepe yes, you can do it with zippers
Is it that I have to first compose the tree first then?
no
one sec I'll show you
(use 'com.rpl.specter)
(require '[com.rpl.specter.zipper :as z])
(def data
[{:id 0}
{:id 1}
{:id 2 :parent-id 1 :val 1}
{:id 3 :parent-id 1 :val 1}
{:id 4 :parent-id 2 :val 2}
{:id 5 :parent-id 3 :val 2}
{:id 6 :parent-id 3 :val 2}
{:id 7 :parent-id 0 :val 100}
{:id 8 :parent-id 7 :val 200}
{:id 9 :parent-id 6 :val 3}])
(def TO-GRAPH (path z/VECTOR-ZIP z/DOWN))
(defn to-node [id]
(z/find-first #(= (:id %) id))
)
(def CHILDREN
(path
(collect-one z/NODE :id)
z/LEFTMOST
z/NEXT-WALK
(collect-one z/NODE :parent-id)
(collected? [id1 id2] (= id1 id2))
DISPENSE
))
(def DESCENDANTS (recursive-path [] p (stay-then-continue CHILDREN p)))
(select [TO-GRAPH (to-node 1) DESCENDANTS z/NODE (must :val)] data)
that said, it's a really bad representation for a tree
You mean my data? Yeah, some legacy stuff. I will try it and report back. Thank you very much for help!
On some bigger trees I am getting Maximum call stack size exceeded in CLJS. Indeed this representation is bad 😞
The thing as always, is that those data I am receiving from API. The call stack is exceeded in the recursive-path
@pepe you can do better with custom navigators rather than zippers
see defnav
navigate to pair of [list-of-nodes index]
, and then make custom CHILDREN
navigator that does the search for indices that are direct children of currently navigated index