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

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

+6
Clojure
重新分类

TL;DR

update-valsupdate-keys本意上是在基于某些标识符的相同数据映射上进行操作的。
https://clojure.atlassian.net/browse/CLJ-2651
https://clojure.atlassian.net/browse/CLJ-1959

但是核心中没有任何函数能够从同质数据的序列中生成这样的映射。我想肯定有很多人找到了实现这种功能的方法,例如

(into {} (map (juxt f identity)) coll) ; credit Sean Corfield
(persistent! (reduce #(assoc! %1 (f %2) %2) (transient {}) coll)) ; from Medley
(update-vals first (group-by f coll)) 

但是我不知道哪个是最高效的。所以我很好奇,在引入update-keysupdate-vals时,key-by函数是否在Clojure核心中留下了缺失的一环?


Clojure 1.11引入了update-keysupdate-vals,我开始使用它们替代自己编写的map-vals等函数。

然而,我仍然不确定如何创建一个可以由update-keysupdate-vals操作的映射。通常情况下,我会从一个数据库中检索到一系列相同类型的映射,如下所示

[{:id 1 :name "brandon"}
 {:id 2 :name "brenda"}
 {:id 3 :name "kelly"}]

并且一个(key-by :id coll)(index-by :id coll)函数会将它转换为

{1 {:id 1 :name "brandon"}
 2 {:id 2 :name "brenda"}
 3 {:id 3 :name "kelly"}}

但是如何做到这一点?update-vals允许

(defn key-by 
  [f coll]
  (update-vals first (group-by f coll)))

但这些集合通常很大,人们希望获得很好的性能。在Medley中,index-by是这样编写的

(defn index-by
  [f coll]
  (persistent! (reduce #(assoc! %1 (f %2) %2) (transient {}) coll)))

它看起来似乎更快,这是我永远也想不到的。所以我免不了要 wonder,是否在引入update-keysupdate-vals时,缺少了Clojure核心中的key-by(这个名字对我来说听起来更好)这一部分?

有一个被请求的函数的抽象化,我没有看到任何人提到,它将涵盖`group-by`和`index-by`

```
(defn group-with [kf vf coll] ...)
;; 其中 kf 是 itm->k,vf 是 v->itm->v'

(def index-by #(group-with %1 (partial apply second) %2))

(def group-by #(group-with %1 (fnil conj []) %2))
```

`group-with` 也会覆盖更广泛的使用情况,目前这些情况需要使用 `reduce`。

编辑:对不起,我对 clojure 还不太了解,我本想将它作为答案发布。

2 个答案

0
by
选择 by
 
最佳答案

https://clojure.atlassian.net/browse/CLJ-2738创建了 jira 请求。

我同意Sean在这里的其它观点,我认为这与update-keys或update-vals或同类值集无关。

by
可能在我想象中,update-vals和update-keys暗示了index-by的存在。不过,我还是非常高兴看到这个在JIRA上,感谢您!
by
一石二鸟,`index-by`可以用这里提出的更通用的`group-by`来实现
https://ask.clojure.org/index.php/12319/can-group-by-be-generalized
0

您的 key-by(into {} (map (juxt :id identity)) coll)(它内部使用了 transducetransient/persistent!)。

这似乎与您使用 update-keysupdate-vals 的用途不相关(我们在某些地方使用了这两个,并且在其他地方也有相似的 key-by)。

是的,我也曾使用 `(into {} (map (juxt :id identity)) coll)` 达到这个目的。但是当 1.11 版本发布时,我发现可以使用 `(update-vals first (group-by :id coll))` 并觉得它更简洁。

关于正交性的问题,我认为我的问题可能不太明确。根据我的理解,`key-by` 生成的类型适用于 `update-vals` 和 `update-keys` 操作的映射类型?我的问题仅仅是,如果认为生成此类映射的 `key-by` 函数也包含在核心中是否太激进,因为 `update-vals` 和 `update-keys` 已包含在核心中。三者并存似乎更加对称。
update-valsupdate-keys 可以作用于任何哈希映射——它们是通用的。
当然是的。但是至少对于 update-vals,预期的使用场景似乎是同质类型映射

https://clojure.atlassian.net/browse/CLJ-2651
"需要应用 update-vals 的映射几乎总是具有同质类型的值!"

当然,这并不是一个请求——只是一个问题:为什么没有这样的功能:将一组同质类型的集合转换为同质类型的索引映射。:-)
...