Here's my problem: I want a function helpme
that takes a map and replaces the keys :r
and :g
with empty vectors if and only if those keys exist. For example:
Input:
(helpme {:a "1" :r ["1" "2" "3"] :g ["4" "5"]})
Output:
{:a "1" :r [] :g []}
Input:
(helpme {:a "1" :r ["1" "2" "3"]})
Output:
{:a "1" :r []}
I can define a function "helpme" that does this, but it's overly complicated, and I feel like there must be an easier (more idiomatic) way...
Here's the overly complicated way I've done, as requested below:
(defn c [new-doc k] (if (contains? new-doc k) (assoc new-doc k []) new-doc))
(defn helpme [new-doc] (c (c new-doc :r) :g))
(defn helpme [m]
(into m (for [[k _] (select-keys m [:r :g])]
[k []])))
Short, and only requires editing in one place when the number of items to set to []
changes.
In my search for a version of update-in which only updated the map if the key actually existed, Google insisted that I could find my answer here. For others in search of the same thing I've created the following helper functions:
(defn contains-in?
[m ks]
(not= ::absent (get-in m ks ::absent)))
(defn update-if-contains
[m ks f & args]
(if (contains-in? m ks)
(apply (partial update-in m ks f) args)
m))
That way you could:
> (def my-data {:a {:aa "aaa"}})
> (update-if-contains my-data [:a :aa] clojure.string/upper-case)
{:a {:aa "AAA"}}
> (update-if-contains my-data [:a :aa] clojure.string/split #" ")
{:a {:aa ["a" "aa"]}}
> (update-if-contains my-data [:a :b] clojure.string/upper-case)
{:a {:aa "aaa"}} ; no change because [:a :b] didn't exist in the map
(defn helpme
[mp]
(as-> mp m
(or (and (contains? m :r) (assoc m :r []))
m)
(or (and (contains? m :g) (assoc m :g []))
m)
m))
if there were a third replacement, I would use this function:
(defn replace-contained [m k v] (or (and (contains? m k) (assoc m k v)) m))
as->
is new in clojure 1.5 but the definition is very simple if you are stuck using an older clojure version:
(defmacro as->
"Binds name to expr, evaluates the first form in the lexical context
of that binding, then binds name to that result, repeating for each
successive form, returning the result of the last form."
{:added "1.5"}
[expr name & forms]
`(let [~name ~expr
~@(interleave (repeat name) forms)]
~name))
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