Clojure: idiomatic update of map value if key exists

Here is my problem: I need a function helpmethat takes a card and replaces the keys :rwith :gempty vectors if and only if these 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 "helpme" function that does this, but it is too complex, and I feel that there should be a simpler (more idiomatic) way ...

Here's a too complicated way that I did as follows:

(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))
+4
source share
6 answers
(defn helpme [m]
  (into m (for [[k _] (select-keys m [:r :g])]
            [k []])))

It is short, and only editing in one place is required when the number of elements to set to changes [].

+9

, ​​, , Google , . , , :

(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))

, :

> (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
+3
(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))

, :

(defn replace-contained [m k v] (or (and (contains? m k) (assoc m k v)) m))

as-> clojure 1.5, , clojure:

(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))
+1

:

(defn helpme [m]
  (merge m
         (apply hash-map (interleave
                          (clojure.set/intersection
                           (set (keys m)) #{:r :g})
                          (repeat [])))))
0

, , , .

(defn clean [m]
  (let [m (if (:r m) (assoc m :r []) m)
        m (if (:g m) (assoc m :g []) m)]
    m))

- , :

(defn cond-assoc [m & kvs]
  (reduce
    (fn [acc [k v]]
      (if (get acc k)
        (assoc acc k v)
        acc))
    m
    (partition 2 kvs)))

(cond-assoc {:a "1" :r ["1" "2" "3"] :g ["4" "5"]}
            :r []
            :g [])  ; {:r [] :a "1" :g []}

(cond-assoc {:a "1" :r ["1" "2" "3"]}
            :r []
            :g [])  ; {:r [] :a "1"}
0
source

Checking the expected key in the comparison function

(sort-by #(if (number? (:priority %))
             (:priority %)
             (java.lang.Integer/MAX_VALUE))
          <
          [{:priority 100} {:priority 10} {:test 1}])




>({:priority 10} {:priority 100} {:test 1})
0
source

All Articles