2024年Clojure调查问卷中分享您的看法!

欢迎!请参阅关于页面以了解更多如何使用本站的信息。

+6
Clojure
重新分类

TL;DR(太长不读)

《update-vals》和《update-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-keys》和《update-vals》,我和其他人开始使用它们代替我们手写的《map-vals》等。

然而,我仍然不确定如何创建一个使得《update-keys》和《update-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-keys》和《update-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在其他地方的观点,我认为这与 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 的映射几乎总是具有同质类型的值。"

当然,这不是一个请求 — 而是询问是否遗漏了这样一个功能:将同质类型集合转换为同质类型索引映射的功能。:-)
...