Clojure:idiomatic更新地图的值如果密钥存在

Sum*_*tch 4 dictionary key clojure

这是我的问题:我想要一个helpme带有地图:r:g用空向量替换的函数,当且仅当这些键存在时.例如:


输入:

(helpme {:a "1" :r ["1" "2" "3"] :g ["4" "5"]})
Run Code Online (Sandbox Code Playgroud)

输出:

{:a "1" :r [] :g []}
Run Code Online (Sandbox Code Playgroud)

输入:

(helpme {:a "1" :r ["1" "2" "3"]})
Run Code Online (Sandbox Code Playgroud)

输出:

{:a "1" :r []}
Run Code Online (Sandbox Code Playgroud)

我可以定义一个功能"helpme"来做到这一点,但它过于复杂,我觉得必须有一个更容易(更惯用)的方式......

这是我完成的过于复杂的方式,如下所述:

(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))
Run Code Online (Sandbox Code Playgroud)

ama*_*loy 9

(defn helpme [m]
  (into m (for [[k _] (select-keys m [:r :g])]
            [k []])))
Run Code Online (Sandbox Code Playgroud)

简短,只需要在一个地方进行编辑,当设置的项目数量[]发生变化时.


Jac*_*cob 6

在我搜索仅在密钥确实存在的情况下才更新地图的 update-in 版本时,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))
Run Code Online (Sandbox Code Playgroud)

这样你就可以:

> (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
Run Code Online (Sandbox Code Playgroud)