replaceclojurenested-map

clojure/clojurescript change just one key in nested map


I have this map:

{:a {:a {:a 1 :b 2}}}

And I want to turn it into this one:

{:a {:a {:x 1 :b 2}}}

I tried this, but -of course- got all :a replaced:

(clojure.walk/postwalk-replace {:a :c} {:a {:a {:a 1 :b 2}}})

-> {:c {:c {:c 1, :b 2}}}

I tried this, but got a result I can't even interpret:

(update-in {:a {:a {:a 1 :b 2}}} [:a :a] clojure.walk/postwalk-replace {:a :c})

-> {:a {:a {1 :c}}}

What can I do?


Solution

  • There is a clojure.set/rename-keys. E.g.

    (update-in {:a {:a {:a 1 :b 2}}} [:a :a] clojure.set/rename-keys {:a :c})
    ; → {:a {:a {:b 2, :c 1}}}
    

    The reason, why your example fails is the argument order. postwalk-replace needs the first argument to be the replacement map and the second argument to what is to be renamed. But update-in always sends the traversed things as first argument into the function. So you need to juggle the arguments around (e.g. via an anon-fn or with partial):

    (update-in {:a {:a {:a 1 :b 2}}} [:a :a] (partial clojure.walk/postwalk-replace {:a :c}))
    ; → {:a {:a {:b 2, :c 1}}}