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)) 

但我不知道哪个最有效。所以,我想知道在核心库中是否存在一个key-by函数,它可以生成一个具有良好性能的映射?


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)))

这看起来更有效率,这是我想不出的事情。所以我禁不住要想,当update-keysupdate-vals被引入时,key-by函数(这个名称听起来更好)是否成为了Clojure核心库的一个缺失的部分?

关于请求的函数有一个我尚未看到的泛化,它涵盖了`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)(在内部使用 transduce 协同 transient/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 的映射都会有同质类型的值。"

当然,这并不是一个请求——而是一个问题:为何没有这样一个函数,可以将一组同构类型转换为同构类型的索引映射。:-)
...