Vector Clojure在指定位置从向量中删除项
有没有一种方法可以根据索引从向量中删除一个项?现在,我正在使用subvec拆分向量并重新创建它。我正在寻找向量的assoc的反面?Vector Clojure在指定位置从向量中删除项,vector,clojure,Vector,Clojure,有没有一种方法可以根据索引从向量中删除一个项?现在,我正在使用subvec拆分向量并重新创建它。我正在寻找向量的assoc的反面?subvec可能是最好的方法。Clojure文档说subvec是“O(1)并且非常快,因为生成的向量与原始向量共享结构,并且没有进行修剪”。另一种方法是遍历向量并构建一个新的向量,同时跳过某些元素,这会更慢 从向量的中间删除元素并不是向量必须擅长的事情。如果必须经常这样做,请考虑使用哈希图,这样就可以使用 DISSOC 见: 在clojuredocs.org 在官
subvec
可能是最好的方法。Clojure文档说subvec
是“O(1)并且非常快,因为生成的向量与原始向量共享结构,并且没有进行修剪”。另一种方法是遍历向量并构建一个新的向量,同时跳过某些元素,这会更慢
从向量的中间删除元素并不是向量必须擅长的事情。如果必须经常这样做,请考虑使用哈希图,这样就可以使用<代码> DISSOC
见:
- 在
clojuredocs.org
- 在官方网站指向的
clojure.github.io
是的-subvec是最快的这里有一个很好的解决方案iv:
(defn index-exclude [r ex]
"Take all indices execpted ex"
(filter #(not (ex %)) (range r)))
(defn dissoc-idx [v & ds]
(map v (index-exclude (count v) (into #{} ds))))
(dissoc-idx [1 2 3] 1 2)
'(1)
还有一种可能性,它应该适用于任何序列,而不是炸弹,如果指数超出范围
(defn drop-index [col idx]
(filter identity (map-indexed #(if (not= %1 idx) %2) col)))
subvec
速度快;与瞬变相结合,它提供了更好的结果
使用Criteriam进行基准测试:
user=> (def len 5)
user=> (def v (vec (range 0 5))
user=> (def i (quot len 2))
user=> (def j (inc i))
; using take/drop
user=> (bench
(vec (concat (take i v) (drop j v))))
; Execution time mean : 817,618757 ns
; Execution time std-deviation : 9,371922 ns
; using subvec
user=> (bench
(vec (concat (subvec v 0 i) (subvec v j len))))
; Execution time mean : 604,501041 ns
; Execution time std-deviation : 8,163552 ns
; using subvec and transients
user=> (bench
(persistent!
(reduce conj! (transient (vec (subvec v 0 i))) (subvec v j len))))
; Execution time mean : 307,819500 ns
; Execution time std-deviation : 4,359432 ns
在更大的长度上,加速比甚至更大;同一台试验台的len
等于10000
表示:1368250 ms
,953565863µs
,314387437µs
,向量库提供对数时间串联和切片。假设您需要持久性,并考虑到您的要求,对数时间解决方案在理论上尽可能快。特别是,它比使用clojure的原生subvec
的任何解决方案都要快得多,因为concat
步骤将任何此类解决方案放入线性时间
(require '[clojure.core.rrb-vector :as fv])
(let [s (vec [0 1 2 3 4])]
(fv/catvec (fv/subvec s 0 2) (fv/subvec s 3 5)))
; => [0 1 3 4]
获取所需的索引可能会更快
(定义a[1 2 3 4 5])
(def索引[0 1 3 4])
(时间(dotimes[n100000](vec(subvec a 0 2)(subvec a 3 5‘‘‘)))
“运行时间:69.401787毫秒”
(时间(dotimes[n 100000](mapv#(a%)索引)))
“运行时间:28.18766毫秒”
对于删除单个项目,这比使用subvec要慢,但是对于删除多个索引,这非常好。对于subvec w/transients版本,您使用了什么clojure版本?追溯到40多年前,有一个for subvec与transient不兼容,因为APersistentVector$SubVector没有实现IEditableCollection
。我假设这就是为什么这个示例将subvec调用封装在(vec(subvec…)
中的原因,尽管在我使用clojure 1.7的测试中,vec
在这种情况下仍然会返回clojure.lang.apResistentVector$SubVector
,这可能是一种优化,但我还没有深入研究clojure的源代码。我认为是1.6.0。它是在这个答案写出来前几个月发布的。您是否可以更新Clojure 1.8?正如@RyanWilson所提到的,您的瞬态示例不适用于1.8。将上一个示例中的vec
替换为[]
适用于Clojure 1.8,但这绝对会破坏性能:(.我能得到的最快速度是(subvec v 0 I)(subvec v j))
,比您在我的电脑上使用subvec中版的快15%左右…
user=> (def len 5)
user=> (def v (vec (range 0 5))
user=> (def i (quot len 2))
user=> (def j (inc i))
; using take/drop
user=> (bench
(vec (concat (take i v) (drop j v))))
; Execution time mean : 817,618757 ns
; Execution time std-deviation : 9,371922 ns
; using subvec
user=> (bench
(vec (concat (subvec v 0 i) (subvec v j len))))
; Execution time mean : 604,501041 ns
; Execution time std-deviation : 8,163552 ns
; using subvec and transients
user=> (bench
(persistent!
(reduce conj! (transient (vec (subvec v 0 i))) (subvec v j len))))
; Execution time mean : 307,819500 ns
; Execution time std-deviation : 4,359432 ns
(require '[clojure.core.rrb-vector :as fv])
(let [s (vec [0 1 2 3 4])]
(fv/catvec (fv/subvec s 0 2) (fv/subvec s 3 5)))
; => [0 1 3 4]