请在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 在其他地方的看法,我认为这与 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)(它在内部使用 transduce 以及 transient/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` 应该操作的映射类型?我的问题是,鉴于 `update-vals` 和 `update-keys` 都是核心函数,一个产生该类型映射的 `key-by` 函数是否也成为核心成员有些奇怪。这似乎是三个函数的对称。
update-vals 和 update-keys 可以在任意哈希图上操作—它们是通用的。
当然,但至少对于 `update-vals` 的预期用例来说,似乎是同质类型的映射。

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

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