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

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

即使提供了“键”也不足以解决某些情况——很想知道我遗漏了哪些情况
by
我同意这一点——merge-with就是这样,如果你需要更多,现有的实用库中有许多选项,无论是小的(比如 http://plumatic.github.io/plumbing/plumbing.map.html#var-merge-with-key)还是大的,比如meander或specter。
+2
by

这是一个晚来的回答,但一个不需要引入任何东西(只需要使用 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
by

此外,也不能一概而论地说有一个单一的合并函数适用于所有键。例如,如果有一个是标量的键,那么 into 作为合并函数会失败,因为它无法从java.lang.Long创建ISeq

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

...