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
selected 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-valsupdate-keys 应该操作的类型。我的问题是,一个生成这种类型映射的 `key-by` 函数是否应该属于核心,因为 `update-vals` 和 `update-keys` 都在核心中。所有的三个函数看起来都很对称:)
update-valsupdate-keys 可以操作任何哈希表——它们是通用的。
当然。但我认为 update-vals 的预期用例似乎是同质类型映射。

https://clojure.atlassian.net/browse/CLJ-2651
"几乎在所有需要使用 update-vals 的映射中,值都是同质类型的。"

当然,这不是一个请求,只是问问是否遗漏了一个将同质类型集合转换为同质类型索引映射的函数。:)
...