请在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` 时才会用。

编辑:对不起,我是 Ask 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`应该操作的那种类型的map。我的问题只是想询问,一个能产生这种类型map的`key-by`函数是否应该属于核心功能,因为`update-vals`和`update-keys`已经在核心中了。这样三者都有,感觉更协调。
头像:
update-valsupdate-keys可以操作任何哈希表——它们是通用的。
头像:
当然。但update-vals的预期用途似乎是同质类型map

https://clojure.atlassian.net/browse/CLJ-2651
"通常需要应用update-vals的map几乎都有同质类型的值。"

当然,这不是一个请求——只是一个问题,是否有人疏忽没有提供一个将同质类型的集合转换为同质类型的索引导出map的函数。:-)
...