【问题标题】:What's the equivalent of Java's computeIfAbsent or putIfAbsent in Clojure?Clojure 中 Java 的 computeIfAbsent 或 putIfAbsent 的等价物是什么?
【发布时间】:2016-06-14 08:56:34
【问题描述】:

使用 Java 中的映射,您可以编写 map.computeIfAbsent(key, f) 来检查映射中是否已经存在键,如果不存在,则在键上调用 f 以生成值,并将其输入映射中。您还有map.putIfAbsent(key, value),它仅在映射中不存在键时才将值放入映射中。

忽略 Java 方法也返回值的事实,而是希望返回新的映射,Clojure 中的等效代码是什么?

到目前为止,我想出的最好的方法就是用类似的东西自己动手

(defn compute-if-absent [map key f]
  (if (key map)
    map
    (assoc map key (f key))))

除了自己滚动还有其他选择吗?

【问题讨论】:

    标签: java dictionary clojure


    【解决方案1】:

    Clojure 映射是不可变的,因此您将始终返回具有更新内容的新映射 - 因此您的函数将始终是线程安全的。这也意味着你不能有一个全局变量来保存你的地图并改变它们。

    您对compute-if-absent 的实现几乎是正确的。对于虚假的键,它将失败,例如{false 1}。您需要更改if 条件并使用contains? 而不是key:

    (defn compute-if-absent [m k f]
      (if (contains? m k)
        m
        (assoc m key (f k))))
    

    如果您确实需要具有与 ConcurrentMap 相同的行为,您可以使用 Clojure 中的 Java 互操作来使用它们。

    【讨论】:

    • 我猜你的意思是“包含?m键”
    • 是的,我已经修好了。
    • 我已将其标记为问题的正确答案,正如我所说的那样,即使现在我认为我实际上是指 z7sg 正在回答的问题——我至少给出了这个答案也投票。
    【解决方案2】:

    更简单的解决方案是使用merge,作为put-if-absent:

    (merge {key val} m)
    

    虽然compute-if-absent 的最终结果是相同的,但不管m 的内容如何,​​以下代码当然会计算(f key):

    (merge {key (f key)} m)
    

    【讨论】:

    • 不要认为它比 Piotr 的更简单(虽然更短):首先您应该始终考虑参数的顺序 merge,其次:您每次都调用 f,即使 key 存在于m 中,所以当值计算繁重时,它是一个巨大的性能损失(如果计算值带有一些副作用,它甚至容易出错)
    • put-if-absent 更简单,但我在答案中确实提到了计算版本。我会考虑使用带有副作用的f,而不是使用merge。
    • 再一次,我不是说merge不好,我只是说在存在的情况下调用函数f是不好的both 并且 map 中没有值,而不是仅在没有 val 时才调用它。也不是说副作用是好的,而是说它们不是不可能的(比如当值生成依赖于某种队列中的项目时,队列中会有很多值“丢失”(检索但不是使用)。或者如果这个 f 函数内部有日志,你可能会很开心地用一大堆不需要的记录来解析结果日志)
    • 我认为compute-if-absent 的全部意义在于仅在需要时生成新值(调用f)(例如,成本高或有副作用)。否则,您始终可以使用put-if-absent 来调用f。
    • 实际上,当我问这个问题时,我只是想用一种方便的方式在地图中放置一些不存在的东西(我想我应该问一下 put-if-absent)。
    【解决方案3】:

    如果您正在尝试实现某种形式的缓存,那么您可以使用 clojure 的出色 memoize 函数。

    例如:(def fast-inc (memoize inc))

    见:http://clojuredocs.org/clojure.core/memoize

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-19
      • 2014-03-15
      • 2014-03-11
      • 1970-01-01
      • 2012-07-03
      • 1970-01-01
      • 2011-03-17
      相关资源
      最近更新 更多