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 时,如果在 Clojure 核心中没有引入key-by(这个名字对我来说更好)作为缺失的部件?

我还没有看到有人提到这个要求的函数的泛化,这个泛化可以同时涵盖 `group-by` 和 `index-by`

```
(defn group-with [kf vf coll] ...)
;; kf is itm->k 和 vf is 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-vals 和 update-keys 可以在任何哈希表上操作,它们是通用的。
是的,当然。但 `update-vals` 的预期用法似乎是同构类型映射

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

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