gpt4 book ai didi

dictionary - 为什么在 Clojure 的 transient 映射中插入 1000 000 个值会生成一个包含 8 个项目的映射?

转载 作者:行者123 更新时间:2023-12-04 01:27:47 25 4
gpt4 key购买 nike

如果我尝试做 1000 000 assoc!在 transient 向量上,我会得到一个包含 1000 000 个元素的向量

(count
(let [m (transient [])]
(dotimes [i 1000000]
(assoc! m i i)) (persistent! m)))
; => 1000000

另一方面,如果我对 map 做同样的事情,它只会有 8 个项目
(count
(let [m (transient {})]
(dotimes [i 1000000]
(assoc! m i i)) (persistent! m)))
; => 8

发生这种情况有什么原因吗?

最佳答案

transient 数据类型的操作不保证它们将返回与传入的引用相同的引用。有时实现可能决定在 assoc! 之后返回一个新的(但仍然是 transient 的)映射。而不是使用您传入的那个。

ClojureDocs page on assoc! 有一个 nice example这解释了这种行为:

;; The key concept to understand here is that transients are 
;; not meant to be `bashed in place`; always use the value
;; returned by either assoc! or other functions that operate
;; on transients.

(defn merge2
"An example implementation of `merge` using transients."
[x y]
(persistent! (reduce
(fn [res [k v]] (assoc! res k v))
(transient x)
y)))

;; Why always use the return value, and not the original? Because the return
;; value might be a different object than the original. The implementation
;; of Clojure transients in some cases changes the internal representation
;; of a transient collection (e.g. when it reaches a certain size). In such
;; cases, if you continue to try modifying the original object, the results
;; will be incorrect.

;; Think of transients like persistent collections in how you write code to
;; update them, except unlike persistent collections, the original collection
;; you passed in should be treated as having an undefined value. Only the return
;; value is predictable.

我想重复最后一部分,因为它非常重要: 您传入的原始集合应被视为具有未定义的值。只有返回值是可预测的。

这是您的代码的修改版本,可以按预期工作:
(count
(let [m (transient {})]
(persistent!
(reduce (fn [acc i] (assoc! acc i i))
m (range 1000000)))))

作为旁注,你总是得到 8 的原因是因为 Clojure 喜欢使用 clojure.lang.PersistentArrayMap (由数组支持的映射)用于具有 8 个或更少元素的映射。一旦超过 8,它就会切换到 clojure.lang.PersistentHashMap .
user=> (type '{1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 a})
clojure.lang.PersistentArrayMap
user=> (type '{1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 a 9 a})
clojure.lang.PersistentHashMap

一旦超过 8 个条目,您的 transient 映射会将支持数据结构从成对数组 ( PersistentArrayMap ) 切换到哈希表 ( PersistentHashMap ),此时 assoc!返回一个新的引用,而不是仅仅更新旧的引用。

关于dictionary - 为什么在 Clojure 的 transient 映射中插入 1000 000 个值会生成一个包含 8 个项目的映射?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29684803/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com