How do I add an element to an array-map in Clojure?

前端 未结 2 1481
野性不改
野性不改 2021-01-24 20:22

How can I add an element to an array-map in Clojure? I tried using assoc but it doesn\'t get added? I essentially want to set a default value of 0 for any missing items in the e

相关标签:
2条回答
  • 2021-01-24 20:59

    To supplement Carcigenicate's answer, another suggestion: I'd use merge or assoc on a map of defaults:

    (merge {:default-1 123 :default-2 234} {:default-1 "foo"})
    => {:default-1 "foo", :default-2 234}
    

    Note that the order of arguments to merge matters i.e. right-most maps take precedence over left-most maps. Your default map values will only "survive" if they're not overridden by additional map(s).

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

    Using assoc in this example has the same effect, and I'd prefer that version.

    0 讨论(0)
  • 2021-01-24 21:10

    You need to starting thinking more functional. Note how all the structures you're using are immutable; they themselves can never change. Your second last line makes a copy of entry, but you never do anything with it; it's just thrown out. There are a few ways of dealing with situations like this where you need to transform a structure over a couple steps:

    • Just use 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)))
      

      Note how the last line uses the def-foo copy, instead of the original entry.

    • Use a threading macro:

          ; 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 is replaced by whatever the previous form evaluated to.

    Note though, that if you ever find yourself using get and assoc on the same object, you might want to consider using update instead, which greatly simplifies everything, especially when paired with the -> threading macro:

    (-> (assoc doc "id" (str (java.util.UUID/randomUUID)))
        (update "foo" #(if (empty? %) 0 %))
        (update "bar" #(if (empty? %) 0 %)))
    

    I had to make some assumptions about what your intent was, because your code has an error that I didn't notice until after I had already submitted my answer. In your original code, your ifs don't evaluate to anything when the condition is false. I'm assuming you just don't want to change anything when they're false.

    0 讨论(0)
提交回复
热议问题