An idiomatic way to β€œupdate” a given key on a Clojure card?

Let's say we have a map that looks something like this:

(def m {:a {:foo "bar"}}) 

Now we would like to update the key: a in m with some new values:

 (def vs {:baz "qux"}) 

If it were Python, we could do something like:

 >>> d = {'a': {'foo': 'bar'}} >>> d['a'].update({'baz': 'qux'}) >>> d {'a': {'foo': 'bar', 'baz': 'qux'}} 

The simplest Clojure equivalent I found was to define a function like this:

 (defn update-key " Updates a given key `k` over a map `m` with a map of values `vs`. " [km vs] (assoc mk (merge (km) vs))) 

Then it is called like this:

 (update-key :am vs) ; => {:a {:foo "bar" :baz "qux"}} 

So my question is: what is the most idiomatic and correct way to achieve the same functionality as the update() method that Python dicts provides?

+6
source share
1 answer

I think you are looking for assoc-in :

 (def m {:a {:foo "bar"}}) (assoc-in m [:a :foo] "qux") ; => {:a {:foo "qux"}} (assoc-in m [:a :baz] "qux") ; => {:a {:foo "bar", :baz "qux"}} 

update-in is similar, and maybe worth a look too. This may actually be closer to your Python example:

 (def m {:a {:foo "bar"}}) (def vs {:baz "qux"}) (update-in m [:a] merge vs) ; => {:a {:foo "bar", :baz "qux"}} 

Update:

Even if the key is the value of a variable (and not a compile-time constant), you can still use both update-in and assoc-in by placing the variable in a vector:

 (def m {:a {:foo "bar"}}) (def k' :baz) (def v' "qux") (assoc-in m [:a k'] v') ; => {:a {:foo "bar", :baz "qux"}} 

You can also programmatically create a key vector:

 (def m {:a {:foo "bar"}}) (def k' :baz) (def v' "qux") (let [ks (conj [:a] k')] (assoc-in m ks v')) ; => {:a {:foo "bar", :baz "qux"}} 
+10
source

All Articles