2024 Clojure 状态调查中分享您的想法!

欢迎!请参阅关于页面,了解有关如何操作的更多信息。

+3
集合

大家好!我们最近发现,在将 `update-vals` 应用到排序列表时,由于集合不可变,排序列表会被转换为未排序的数组/散列映射。以下提供了一个示例。值得注意的是,这与 `medley/map-vals` 不同,后者保留了排序,并且我们之前在 1.11 之前使用 `medley/map-vals` 进行此功能。

这是否是预期行为?如果是这样,我想知道其背后的意图 :) 感谢!

user> (def m (sorted-map :a 0 :b 0))
;; => #'user/m
user> (type m)
;; => clojure.lang.PersistentTreeMap
user> (type (update-vals m inc))
;; => clojure.lang.PersistentArrayMap
user> (type (medley.core/map-vals inc m))
;; => clojure.lang.PersistentTreeMap

2 个回答

+3

被选中
 
最佳回答

是的,这是预期行为。在通用性映射类型和性能方面存在权衡。两种选项都已被考虑,最终决定,大多数常见类型的性能(即散列和数组映射)是这里的更高关注点。

如您在文档字符串中所说,此函数返回 "新映射",不对映射类型进行保留。

刚刚碰到这种无意义的做法。考虑到许多其他函数都保留了类型,这是逻辑预期,文档中也几乎没有提及相反的内容。函数文档中提到该函数返回“一个新的映射”,但这并不表明类型发生了变化。我们在处理不可变数据结构,当然函数会返回一个新的映射,它几乎不可能做其他的事情。
0 投票

这种设计是故意的,是为了性能。有序映射主要用于调试。

如果您想使您的有序映射正常工作,请使用此答案下面的代码

```clojure
(defn update-vals
  "m f => {k (f v) ...}

  Given a map m and a function f of 1-argument, returns a new map where the keys of m
  are mapped to result of applying f to the corresponding values of m."
  {:added "1.11"}
  [m f]
  (with-meta
    (persistent!
      (reduce-kv (fn [acc k v] (assoc! acc k (f v)))
        (if (instance? clojure.lang.IEditableCollection m)
          (transient m)
          (transient (empty m)))
        m))
    (meta m)))

(update-vals
  (sorted-map
    :d :e
    :b :c
    :h :a
    :a :g
    )
  str)
```

错误

```clojure
1. Unhandled java.lang.ClassCastException
   class clojure.lang.PersistentTreeMap cannot be cast to class clojure.lang.IEditableCollection
   (clojure.lang.PersistentTreeMap and clojure.lang.IEditableCollection are in unnamed module of loader 'app')
```

与有序映射一起工作的代码,但速度较慢

```clojure
(defn update-vals
  "m f => {k (f v) ...}

  Given a map m and a function f of 1-argument, returns a new map where the keys of m
  are mapped to result of applying f to the corresponding values of m."
  {:added "1.11"}
  [m f]
  (with-meta
    (reduce-kv (fn [acc k v] (assoc acc k (f v)))
      (empty m)
      m)
    (meta m)))
```
感谢,但我看不出`update-vals`为什么不能在有序映射上使用保持排序的逻辑,同时保持无序映射的性能,因此我怀疑这个函数不支持有序映射是否是有意为之,据我所知没有相关文档 :)
我发布的代码已被编辑以在有序映射上工作,这就是`(transient (empty m))`所做的工作。这段代码会抛出错误。我猜测`assoc!`不能在有序映射上工作。

`(assoc! (sorted-map :a :b) :c :d)` 抛出错误
在第一个例子中,我使用了transients。尽管在第二个例子中出了点错。
=>(assoc! (transient (sorted-map :a :b)) :c :d)
没有为类型 object: {:a :b} 定义协议方法 IEditableCollection.-as-transient
我不明白这个点
>> 排序的映射主要用在调试中
在我看来,排序的映射看起来是一个合适的数据结构。不确定调试在这里如何适用。
...