Contrived example to illustrate:
(def nest1 {:a {:b {:c "foo"}}})
(def nest2 {:d {:e "bar"}})
If I wanted to conj these nests at arbitrary levels, I could explicitly do this:
(conj (-> nest1 :a :b) (-> nest2 :d)) ; yields {:e "bar", :c "foo"}
(conj (-> nest1 :a) (-> nest2 :d)) ; yields {:e "bar", :b {:c "foo"}}
But what if I wanted to create a function that would accept the "depth" of nest1 and nest2 as parameters?
; Does not work, but shows what I am trying to do
(defn join-nests-by-paths [nest1-path nest2-path]
(conj (-> nest1 nest1-path) (-> nest2 nest2-path))
And I might try to call it like this:
开发者_StackOverflow社区; Does not work
(join-nests-by-paths '(:a :b) '(:d))
This doesn't work. I can't simply pass each "path" as a list to the function (or maybe I can, but need to work with it differently in the function).
Any thoughts? TIA... Sean
Use get-in:
(defn join-by-paths [path1 path2]
(conj (get-in nest1 path1) (get-in nest2 path2)))
user> (join-by-paths [:a :b] [:d])
{:e "bar", :c "foo"}
user> (join-by-paths [:a] [:d])
{:e "bar", :b {:c "foo"}}
Your version is actually doing something like this:
user> (macroexpand '(-> nest1 (:a :b)))
(:a nest1 :b)
which doesn't work, as you said.
get-in
has friends assoc-in
and update-in
, all for working with nested maps of maps. There's a dissoc-in
somewhere in clojure.conrtrib.
(In Clojure it's more idiomatic to use vectors instead of quoted lists when you're passing around sequential groups of things.)
精彩评论