如何在Clojure中向数组地图添加元素?我尝试使用assoc,但它没有添加?我基本上想要为条目数组映射中的任何缺失项设置默认值0。
(defn create-entry [doc]
(let [entry (assoc doc "id" (str (java.util.UUID/randomUUID)))]
(if (empty? (get entry "foo")) (assoc entry "foo" 0))
(if (empty? (get entry "bar")) (assoc entry "bar" 0))))
Carcigenicate评论后更新:
(defn entry [doc]
(as-> (assoc doc "id" (str (java.util.UUID/randomUUID))) e
(if (empty? (get e "foo")) (assoc e "foo" 0) e)
(if (empty? (get e "bar")) (assoc e "bar" 0) e)))
(defn create-entry [doc]
(prn (entry doc)))
答案 0 :(得分:2)
你需要开始思考更多功能。请注意您使用的所有结构是如何不可变的;他们自己永远不会改变。你的第二行最后一行是entry
的副本,但你从不做任何事情;它被抛弃了。有几种方法可以处理这样的情况,你需要在几个步骤中转换结构:
只需使用let
:
(let [entry (assoc doc "id" (str (java.util.UUID/randomUUID)))
def-foo (if (empty? (get entry "foo")) (assoc entry "foo" 0) entry)]
(if (empty? (get def-foo "bar")) (assoc def-foo "bar" 0) def-foo)))
请注意最后一行如何使用def-foo
副本,而不是原始entry
。
使用线程宏:
; Create a new binding, e, that will hold the result of the previous form
(as-> (assoc doc "id" (str (java.util.UUID/randomUUID))) e
(if (empty? (get e "foo")) (assoc e "foo" 0) e)
(if (empty? (get e "bar")) (assoc e "bar" 0) e))
e
将被之前评估的形式所取代。
但请注意,如果您发现自己在同一个对象上使用get
和assoc
,则可能需要考虑使用update
,这极大地简化了所有内容,尤其是配对时使用->
线程宏:
(-> (assoc doc "id" (str (java.util.UUID/randomUUID)))
(update "foo" #(if (empty? %) 0 %))
(update "bar" #(if (empty? %) 0 %)))
我必须对你的意图做出一些假设,因为你的代码有一个错误,直到我提交了我的答案之后我才注意到。在原始代码中,当条件为false时,if
s不会评估任何内容。我假设你只是在他们错误时不想改变任何东西。
答案 1 :(得分:2)
补充Carcigenicate的回答,另一个建议是:
我在默认地图上使用merge
或assoc
:
(merge {:default-1 123 :default-2 234} {:default-1 "foo"})
=> {:default-1 "foo", :default-2 234}
请注意,merge
的参数顺序很重要,即最右边的地图优先于最左边的地图。您的默认地图值只会"幸存"如果他们没有被其他地图覆盖。
(def defaults {"foo" 0, "bar" 0})
(defn create-entry [doc]
(assoc defaults "id" (str (java.util.UUID/randomUUID))))
(defn create-entry [doc]
(merge defaults {"id" (str (java.util.UUID/randomUUID))}))
在此示例中使用assoc
具有相同的效果,我更喜欢该版本。