请在2024年Clojure状态调查!分享你的想法。

欢迎!请查看关于页面,了解更多关于这里如何工作的小信息。

0
Clojure

有时,根据数据的语义合并很重要。不幸的是,current 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)

寻找解决方案时意外发现了meander :)

对某些情况而言,“提供键”甚至还不够 —— 好奇我错过了哪些情况
我同意这一点 —— merge-with就是它所是的东西,如果你需要更多,现有实用库中有很多选择,无论是小的(如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

...