Reputation: 477
Alright, I'm new to clojure, this should be easy but for the life of me I can't find the answer
Let's say I have this map
(def mymap {:a 10 :b 15})
Now I want to change the value of :a to 5. I don't know how to do this properly
I know update
and assoc
can make changes but they both receive a function as last argument, which applies to the value. I don't want that, I don't want any function to run, I just want to simply set :a to 5.
I think I can pass an anonymous function that simply returns 5 and ignores the arg, but is this the right way? Doesn't look good to me
(update mymap :a (fn [arg] 5))
Upvotes: 8
Views: 10486
Reputation: 45741
assoc
does not take a function as its last argument; unless you were wanting to associate a function with a key in the map. (assoc mymap :a 5)
does what you want.
I'll add though, update
, which does take a function, could be used here as well when combined with constantly
or just another function (although there's no reason to use them over assoc
):
; constantly returns a function that throws away any arguments given to it,
; and "constantly" returns the given value
(update mymap :a (constantly 5))
; Basically the same as above
(update mymap :a (fn [_] 5))
Upvotes: 11
Reputation: 1275
Do keep in mind that as mymap is immutable, so calling (update mymap :a (constantly 5))
or (assoc mymap :a 5)
will return a map {:a 5 :b 15}
, further references to mymap will continue to return the original value of {:a 10 :b 15}
.
If you want to update the value for later calls, you can look at using atoms.
(defonce mymap (atom {:a 10 :b 15}))
(defn change-mymap [value]
(swap! mymap #(assoc % :a value)))
Just make sure that when you want to reference the value of an atom, you dereference it with the @ symbol. For example: (clojure.pprint/pprint @mymap)
When you call (change-mymap 5)
this will update the stored mymap value to set :a
to a new value, leaving any other key-value pairs in your map alone. This can be helpful when you are mapping in updated state in client/server code when responding to inputs from the other system.
Also note that for nested maps, such as
(defonce nested (atom {:a "a value"
:b {:inner "Another value"
:count 3
:another {:value 5}}}))
You can address a particular value in your map by a path vector. You can use the get-in
function to retrieve the value (get-in @nested [:b :another :value])
and you can use assoc-in
or update-in
with a path to update the values. This also allows you to extend a map. For example, with the above value of nested, you can add a whole section to the tree:
(swap! nested #(assoc-in % [:a :b :c :d] "foo"))
will update the initial map to look like this:
{:a {:b {:c {:d "foo"}}}
:b {:inner "Another value"
:count 3
:another {:value 5}}}
Upvotes: 3