将默认值应用于地图

时间:2013-09-20 16:08:02

标签: clojure

我正在寻找一种方法来应用一些默认值来映射。我知道以下工作:

(defn apply-defaults
  [needing-defaults]
  (merge {:key1 (fn1 10)
          :key2 (fn2 76)}
          needing-defaults))

上述问题是即使fn1可能已经拥有这些密钥,也会评估fn2needing-defaults的值 - 因此从不需要它们。

我尝试过合并但这似乎不起作用。我对此很陌生 - 有什么建议吗?

4 个答案:

答案 0 :(得分:3)

我通常使用merge-with函数来应用默认值:

(merge-with #(or %1 %2) my-map default-map)

但在你的情况下它应该是这样的:

(reduce (fn [m [k v]]
          (if (contains? m k) m (assoc m k (v))))
        needing-defaults
        defaults)

其中defaults是函数映射:

{ :key1 #(fn1 10)
  :key2 #(fn2 76)}

if是一种特殊形式,因此它会更新评估其false分支。

See my example for more info

答案 1 :(得分:0)

如果我理解你的问题,那怎么样?

(defn apply-defaults [nd]
    (into {:key1 (sf1 10) :key2 (sf2 76)} nd))

答案 2 :(得分:0)

由于您可以将nil合并到地图中,因此您可以使用if-not宏:

(merge {} nil {:a 1} nil) ;; {:a 1}

试试这个:

(defn apply-defaults [col]
  (merge col
    (if-not (contains? col :key1) {:key1 (some-function1 10)})
    (if-not (contains? col :key2) {:key2 (some-function2 76)})))

some-function1some-function2只会在col尚未拥有密钥时执行。

答案 3 :(得分:0)

您可以使用宏来生成contains?检查并使函数调用短路。

(defmacro merge-with-defaults [default-coll coll]
  (let [ks (reduce (fn [a k] (conj a
                                   `(not (contains? ~coll ~k))
                                   `(assoc ~k ~(k default-coll))))
                   [] (keys default-coll))]
    `(cond-> ~coll ~@ks)))


(defn apply-defaults [needing-defaults]
  (merge-with-defaults {:key1 (fn1 10)
                        :key2 (fn2 76)}
                       needing-defaults))

请记住将函数调用保留在merge-with-defaults的调用中以防止评估。