请分享您的想法,参与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 投票

选中
 
最佳答案

https://clojure.atlassian.net/browse/CLJ-2738 创建 JIRA 请求

我同意 Sean 此处 elsewhere 的看法,我认为这和 update-keys 或 update-vals,或同质值集合没有关系。

可能这只是我自己的想法,update-vals 和 update-keys 形式上暗示了 index-by 应该存在。不过,我很高兴看到它在 JIRA 上,谢谢!
一石二鸟,`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 的映射都具有同质类型的值! "

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