another question, how would you write this:
(take the key of map represented as vector into the value as the key :name. it's a nested structure)
{:id 0
:children [:child-1 {:id 1}
:child-2 {:id 2
:children [:child-3 {:id 3}]}]}
to:
{:id 0
:children [:child-1 {:id 1 :name :child-1}
:child-2 {:id 2 :name :child-2
:children [:child-3 {:id 3 :name :child-3}]}]}
I don't like the fact that I'm using stay twice 😕
Yesterday I tried it without specter, and I'm not sure what I like better:
(defn attach-names [app]
(if (:children app)
(update app :children #(->> %
(partition 2)
(mapv (fn [[k v]] [k (assoc (attach-names v) :name k)]))
flatten
vec))
app))I just couldn't wrap my head around how to do it with specter, and the way you wrote it doesn't seem to me straightforward as just "normal" clj code
i think you can replace (mapv + flatten) by mapcat
perfect!
you can also mix the two solutions: use clojure for recursion, and replace the update fn by (transform [(view #(partition 2 %) (collect-one FIRST) LAST] (fn [c v] (assoc v ;name c) ...)
hmm no that would be even longer code
a way to collect the name to apply to the node: [(view #(apply hash-map %)) ALL (collect-one FIRST) LAST]
a way to navigate to every node:
(recursive-path [] p
(if-path #(and (map? %) (contains? % :children))
(stay-then-continue :children (view #(apply hash-map %)) MAP-VALS p) STAY))
combining the two:
(def nodes
(recursive-path [] p
(if-path #(and (map? %) (contains? % :children))
(stay-then-continue :children (view #(apply hash-map %)) ALL DISPENSE (collect-one FIRST) LAST p)
STAY)))
(transform nodes (fn ([v] v) ([c v] (assoc v :name c)))
{:id 0
:children [:child-1 {:id 1}
:child-2 {:id 2
:children [:child-3 {:id 3}]}]})