What would be an elegant way to find the ba4
values for :foo
in a data structure like:
[[{:foo "ba1"}{:foo "ba2"}] [{:foo "ba3"}{:foo "ba4"}]]
and add the :bif "baf"
key and value so the map(s) containing the key/value I sought so I had:
[[{:foo "ba1"}{:foo "ba2"}] [{:foo "ba3"}{:foo "ba4" :bif "baf"}]]
?
This is the main thing I am trying to figure out; I do wonder about how you would do this if there were multiple levels of nested maps, but that will be next for me to understand.
I have, I think, seen various libraries out there for tackling this sort of thing and I'm not at all against using them, though they would have to work in ClojureScript.
I am trying to update a Reagent atom such that classes will change on a UI element.
(I learned a bit about decorators and merge
from Rulle's solution.)
What you're describing is walking a nested data structure. Postwalking or prewalking take every possible subform of your nested data structure and applies a function against it.
Here's how I got your desired solution using postwalk
(note: assoc
adds a key-value to a map):
(ns walking.core
(:require [clojure.walk :as w]))
(clojure.walk/postwalk #(if (and (map? %) (= (:foo %) "ba4")) (assoc % :bif "baf") %)
[[{:foo "ba1"} {:foo "ba2"}] [{:foo "ba3"} {:foo "ba4"}]])
;;=> [[{:foo "ba1"} {:foo "ba2"}] [{:foo "ba3"} {:foo "ba4", :bif "baf"}]]
And it works no matter how nested it gets:
(clojure.walk/postwalk #(if (and (map? %) (= (:foo %) "ba4")) (assoc % :bif "baf") %)
[[{:foo "ba1"} {:foo "ba2"}] [[{:foo "ba3"} {:test {:foo "ba4"}}]]])
;;=> [[{:foo "ba1"} {:foo "ba2"}] [[{:foo "ba3"} {:test {:foo "ba4", :bif "baf"}}]]]
Why postwalk
instead of prewalk
? Both work.
(clojure.walk/prewalk #(if (and (map? %) (= (:foo %) "ba4")) (assoc % :bif "baf") %)
[[{:foo "ba1"} {:foo "ba2"}] [{:foo "ba3"} {:foo "ba4"}]])
;;=> [[{:foo "ba1"} {:foo "ba2"}] [{:foo "ba3"} {:foo "ba4", :bif "baf"}]]
You don't have to lein install
anything, and it's part of Clojure; you just have to require it.