I'm familiar with clojure.walk/prewalk and clojure.walk/postwalk
I want something like clojure.walk/prewalk and clojure.walk/postwalk -- but I also want the path required to get to the node -- whereas prewalk/postwalk only gives me the nodes, w/o the actual path.
So if we had a structure
[ {:cat "Garfield", :dog "DogeCoin"} [:a :b {:site "so"}]]
then I want my function called with args:
[] [ {:cat "Garfield", :dog "DogeCoin"} [:a :b {:site "so"}]]
[0] {:cat "Garfield", :dog "DogeCoin"}
[1] [:a :b {:site "so"}]
[0 :cat] "Garfield"
...
Is there a builtin for the above? where the processing function receives both the node and the path (from the root node) to the node)?
Thanks!
(based on what fl00r suggested)
(defn pathwalk [f cur-path node]
(let [f1 #(pathwalk f (conj cur-path %1) %2)]
(f cur-path node)
(cond
(map? node) (map #(apply f1 %) node)
(or (vector? node) (list? node)) (keep-indexed f1 node))))
I suppose you also want 'pathwalk' to return something from function f similar to clojure.walk/prewalk and not rely on side-effect? E.g.
(prewalk #(if (= :a %) :c %) [:a :b])
=>
[:c :b]
If yes, then you can do this:
(defn pathwalk [f path e]
(let [e' (f path e)]
(cond
(map? e') (->> e'
(map (fn [[k x]] [k (pathwalk f (conj path k) x)]))
(into (empty e')))
(coll? e') (->> e'
(map-indexed (fn [i x] (pathwalk f (conj path i) x)))
(into (empty e')))
:else e')))
Here is a test run:
(pathwalk #(do
(println %1 %2)
(if (= :a %2)
:c
%2))
[]
[ {:cat "Garfield", :dog "DogeCoin"} [:a :b {:site "so"}]])
it will print:
[] [{:cat Garfield, :dog DogeCoin} [:a :b {:site so}]]
[0] {:cat Garfield, :dog DogeCoin}
[0 :cat] Garfield
[0 :dog] DogeCoin
[1] [:a :b {:site so}]
[1 0] :a
[1 1] :b
[1 2] {:site so}
[1 2 :site] so
and below data will be returned from the function:
[{:cat "Garfield", :dog "DogeCoin"} [:c :b {:site "so"}]]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With