2024 Clojure状态调查!中分享您的想法。

欢迎!请查看关于页面以了解更多关于这个工作方式的信息。

0
Clojure

有时基于数据的语义进行合并是很重要的。不幸的是,当前merge-with的实现需要根据数据类型(值)猜测需要做什么。然而,语义要求了解我们正在尝试合并的键。

例如,在我们的应用中,键:messages是一个数组,需要在合并时进行连接,而键:tags则需要在合并时替换为最新值。

(merge-with into 
   {:messages [1 2 3] :tags [1 1 1]} 
   {:messages [4] :tags [4 4 4]}) 

=> {:messages [1 2 3 4] :tags [1 1 1 4 4 4]} ;; got
=> {:messages [1 2 3 4] :tags [4 4 4]} ;; expected

由于当前merge-with从未向合并函数提供键,因此没有方法来做这件事。

3 个答案

+1

选中
 
最佳答案

merge-with是一个非常出色的小工具,但它并不是万能的。甚至“提供键”对于某些情况也不足以解决问题。幸运的是,merge-with不是原生的;您完全可以自定义一个做您需要做的事情的函数!有一些现成的选项,功能丰富: “Meander” (https://github.com/noprompt/meander) 和 “Specter” (https://github.com/redplanetlabs/specter)

在我寻找解决方案的时候,偶然发现了这个:)

即使是在“提供键”的情况下,也未必足够,对于一些情况我错过了什么,我很感兴趣。
我同意这个观点 - merge-with 只是其本身而已,如果需要更多,现有实用库中有许多选项,无论是小到(如 http://plumatic.github.io/plumbing/plumbing.map.html#var-merge-with-key),还是大量类似 meander 或 specter 的事情。
+2

这是一个迟来的答案,但是要使用一个不带任何额外东西的干净解决方案的话,可以使用 reduce-kv 而不是 merge-with

(defn newer [x y] (if (pos? (compare x y)) x y))
(defn combine [m k v]
  (case k
    :messages (update m k into v)
    :tags (update m k newer v)))
(reduce-kv combine
  {:messages [1 2 3] :tags [1 1 1]}
  {:messages [4] :tags [4 4 4]})
;; => {:messages [1 2 3 4] :tags [4 4 4]}
0

另外,永远不应该假设有一个适用于所有键的单个合并函数。例如,如果有一个键是标量数字,那么作为合并函数的 into 将失败

IllegalArgumentException 不知如何从 java.lang.Long 创建 ISeq

...