这是我的问题:我想要一个函数helpme
,它接受一个映射,并用空向量替换键:r
和:g
当且仅当这些键存在时。例如:
输入:
(helpme {:a "1" :r ["1" "2" "3"] :g ["4" "5"]})
输出:
{:a "1" :r [] :g []}
输入:
(helpme {:a "1" :r ["1" "2" "3"]})
输出:
{:a "1" :r []}
我可以定义一个执行此功能的“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))
答案 0 :(得分:9)
(defn helpme [m]
(into m (for [[k _] (select-keys m [:r :g])]
[k []])))
简短,只需要在设置为[]
的项目数更改时在一个位置进行编辑。
答案 1 :(得分:4)
在我搜索更新版本时,只有在密钥确实存在时才更新地图,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
答案 2 :(得分:1)
(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))
答案 3 :(得分:1)
为此目的使用cond->会怎样?
(defn helpme [m]
(cond-> m
(:r m) (assoc :r [])
(:g m) (assoc :g [])))
答案 4 :(得分:0)
一个选项:
(defn helpme [m]
(merge m
(apply hash-map (interleave
(clojure.set/intersection
(set (keys m)) #{:r :g})
(repeat [])))))
答案 5 :(得分: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"}
答案 6 :(得分:0)
通过测试比较函数中的预期键
(sort-by #(if (number? (:priority %))
(:priority %)
(java.lang.Integer/MAX_VALUE))
<
[{:priority 100} {:priority 10} {:test 1}])
>({:priority 10} {:priority 100} {:test 1})
答案 7 :(得分:0)
我真的很喜欢helpme API包含要重置的键和要重置为的默认值:
(defn helpme [m & {:keys [ks v]
:or {ks #{:r :g}
v []}}]
(apply assoc m (-> m
;; select only existing keys by selecting from original map
(select-keys ks)
keys
;; generate defaults for each (handled by applying `assoc`)
(interleave (repeat v)))))
这通过产生assoc
的变体形式作为参数。
如果您放弃通用API,它可能会很短:
(defn helpme [m]
(apply assoc m (-> m
(select-keys #{:r :g})
keys
(interleave (repeat [])))))