Given add-ref
and parse-tree
in the following snippet, is there a way to combine this pair of transform/traverse into a single traversal (to improve performance by not requiring a multi-pass of a large datastructure?)
(def NODE
(sp/recursive-path [] p
(sp/continue-then-stay
(sp/must :children)
sp/MAP-VALS
p)))
(def terminal2
(sp/richnav [afn]
(sp/select* [this vals structure next-fn]
(throw (Exception. "'terminal2' should only be used in multi-transform")))
(sp/transform* [this vals structure next-fn]
(afn vals structure))))
(def nodes-with-refs
(sp/recursive-path [] p
(sp/continue-then-stay
(sp/putval :children)
(sp/must :children)
sp/ALL
(sp/collect-one sp/FIRST)
sp/LAST
p)))
(defn add-ref [root]
(sp/multi-transform
[(sp/putval :root)
:root
nodes-with-refs
:ref
(terminal2 (fn [vals _] (ref/unparse vals)))]
root))
(defn parse-tree [root]
(reduce
(fn [result item]
(if-let [parsed (parse-node item)]
(conj result parsed)
result))
[]
(sp/traverse [:root :children MAP-VALS NODE] root)))
(->> test-segment ;; potentially large datastructure with form {:root {:name "root" .. :children {..}}}
add-ref ;; add path down the tree to each node in the tree, e.g., "/a/b/c" where A, B, C are nodes with names a, b, c
parse-tree)
@dadair can you just collect the path in parse-tree
?
besides that, the latest release adds vtransform
which eliminate the need for you to do multi-transform
with custom terminal2
you might benefit here from a new vselect
which navigates to [collected-vals navigated-value]
Thanks for pointing out vtransform
, cleans up the code! I’m not quite sure how I would go about collecting the path in parse-tree, and passing those collected values into the reducing function.
hmm, are you suggesting that I could change the sp/traverse
call to a vselect
, and then item
in the reduce would be [collected navigated]
?