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

欢迎!请参阅关于页面,了解有关此如何运作的更多信息。

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 答案

回答
选定
 
最佳答案

merge-with是一个小巧的工具,但它不能解决所有问题。即使是“提供键”在一些情况下也不够。幸运的是,merge-with不是一个原始函数;您可以自由地创建自己的函数来完成您需要的功能!以下是一些带有许多附加功能的现成选项:“Meander”(https://github.com/noprompt/meander)和“Specter”(https://github.com/redplanetlabs/specter)。

我在寻找解决方案时偶然发现了环路 :)

即使“提供键”在某些情况下也不足以解决问题——想知道我错过了哪些情况
我同意这一点——merge-with 就是这样,如果你想要更多,existing utility libs 中有很多选项可供选择,无论大小(如 http://plumatic.github.io/plumbing/plumbing.map.html#var-merge-with-key )还是大型项目,比如 meander 或 specter。
+2 投票

这是一个迟来的答案,但要使用干净的操作而不引入 clojure.core 之外的任何内容,可以使用 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

...