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)

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

某些情况下,“提供键”甚至都不够——好奇我错过了哪些情况
我同意这一点——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 未知如何创建ISeq从:java.lang.Long

...