I want to add an entry to a map but only if the map does not contain the key that I want to add. I.e. I want to do insert but not update. For his I created 2 functions:
(defn assoc-if [pred coll k v]
(if pred (assoc coll k v) coll))
(defn assoc-if-new [coll k v]
(assoc-if (not (contains? coll k)) coll k v))
My question is, do these two functions not exist already?
Also, I'm pretty new to Clojure, any tips on the implementation?
With merge
the right hand map will always overwrite the left hand map so if you reverse your arguments and put them in a map you get the same behaviour:
(assoc-if-new {:a 1 :b 2} :b 3)
;=> {:a 1, :b 2}
(assoc-if-new {:a 1 :b 2} :c 3)
;=> {:c 3, :a 1, :b 2}
(merge {:b 3} {:a 1 :b 2})
;=> {:a 1, :b 2}
(merge {:c 3} {:a 1 :b 2})
;=> {:b 2, :a 1, :c 3}
In other words:
(defn assoc-if-new [coll k v] (merge {k v} coll))
(defn assoc-if [pred coll k v]
(if (pred coll k) (assoc coll k v) coll))
(defn assoc-if-new [coll k v]
(assoc-if (complement contains?) coll k v))
You made a couple of errors:
In
(defn assoc-if [pred coll k v]
(if pred (assoc coll k v) coll))
... pred
is not called. Being neither false
nor nil
, its function value will evaluate true. So the function will always return (assoc coll k v)
.
In
(defn assoc-if-new [coll k v]
(assoc-if (not (contains? coll k)) coll k v))
... the first argument to assoc-if
should be a predicate - a function returning a value used for its truth or falsehood. (not (contains? coll k))
will produce a boolean value, causing an error when assoc-if
tries to call it as a function.
assoc-if
concocts the call
internally.contains?
to a function that returns the logically inverted result.
The standard function complement
does this.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With