clojure assoc-if和assoc-if-new

shm*_*111 7 clojure

我想在地图中添加一个条目,但前提是地图不包含我想要添加的密钥.即我想要插入但不更新.为了他,我创造了2个功能:

(defn assoc-if [pred coll k v]
  (if pred (assoc coll k v) coll))

(defn assoc-if-new [coll k v]
  (assoc-if (not (contains? coll k)) coll k v))
Run Code Online (Sandbox Code Playgroud)

我的问题是,这两个功能已不存在吗?

另外,我对Clojure很新,有关实现的任何提示吗?

opt*_*evo 16

使用merge右手地图将始终覆盖左手地图,因此如果您反转参数并将它们放在地图中,您将获得相同的行为:

(assoc-if-new {:a 1 :b 2} :b 3)
;=> {:a 1, :b 2}

(assoc-if-new {:a 1 :b 2} :c 3)
;=> {:c 3, :a 1, :b 2}

(merge {:b 3} {:a 1 :b 2})
;=> {:a 1, :b 2}

(merge {:c 3} {:a 1 :b 2})
;=> {:b 2, :a 1, :c 3}
Run Code Online (Sandbox Code Playgroud)

换一种说法:

(defn assoc-if-new [coll k v] (merge {k v} coll))
Run Code Online (Sandbox Code Playgroud)

  • @optevo解决方案很聪明,但是会降低性能。如果将“ assoc-if-new”功能用于大型地图并需要大量计算,我肯定会使用@Mars解决方案。使用[criterium](https://github.com/hugoduncan/criterium)基准测试,使用@Mars解决方案“ assoc-if-new” 100000 kv对需要5.3ms **,使用@Mars解决方案需要25.9 ** @optevo的`合并`。 (2认同)

Thu*_*ail 5

(defn assoc-if [pred coll k v]
  (if (pred coll k) (assoc coll k v) coll))

(defn assoc-if-new [coll k v]
  (assoc-if (complement contains?) coll k v))
Run Code Online (Sandbox Code Playgroud)

你犯了几个错误:

(defn assoc-if [pred coll k v]
  (if pred (assoc coll k v) coll))
Run Code Online (Sandbox Code Playgroud)

...... pred没有被召集.既不是false也不是nil,它的功能价值将评估为真.因此该函数将始终返回(assoc coll k v).

(defn assoc-if-new [coll k v]
  (assoc-if (not (contains? coll k)) coll k v))
Run Code Online (Sandbox Code Playgroud)

...第一个参数assoc-if应该是一个谓词 - 一个函数返回一个用于其真或假的值.(not (contains? coll k))将产生一个布尔值,在assoc-if尝试将其作为函数调用时导致错误.

  • 不要显式提供参数:assoc-if在内部调用调用.
  • 如果要反转逻辑结果,则必须使函数 适应 返回逻辑反转结果contains?函数.标准功能就是complement这样做的.