Clojure Remove item from Vector at a Specified Location
截至目前,有没有一种方法可以从基于索引的向量中删除项目,我正在使用subvec拆分向量并再次重新创建它。 我在寻找assoc的反向矢量吗?
从向量中间删除元素不一定是向量所擅长的。如果必须经常执行此操作,请考虑使用哈希映射,以便可以使用
看到:
-
clojuredocs.org 处的subvec -
官方网站指向的
clojure.github.io 上的subvec。
1 2 3 4 | (defn vec-remove "remove elem in coll" [pos coll] (vec (concat (subvec coll 0 pos) (subvec coll (inc pos))))) |
1 2 3 4 5 | user=> (def a [1 2 3 4 5]) user=> (time (dotimes [n 100000] (vec (concat (take 2 a) (drop 3 a))))) "Elapsed time: 1185.539413 msecs" user=> (time (dotimes [n 100000] (vec (concat (subvec a 0 2) (subvec a 3 5))))) "Elapsed time: 760.072048 msecs" |
是的-Subvec最快
向量库
1 2 3 4 | (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] |
这是一个很好的解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 | (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) |
使用标准进行基准测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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 |
长度越大,加速越大;
获得所需的索引可能会更快。
1 2 3 4 5 6 7 8 9 | (def a [1 2 3 4 5]) (def indexes [0 1 3 4]) (time (dotimes [n 100000] (vec (concat (subvec a 0 2) (subvec a 3 5))))) "Elapsed time: 69.401787 msecs" (time (dotimes [n 100000] (mapv #(a %) indexes))) "Elapsed time: 28.18766 msecs" |
如果索引超出范围,则另一种可能性应该适用于任何序列,而不是炸弹...
1 2 | (defn drop-index [col idx] (filter identity (map-indexed #(if (not= %1 idx) %2) col))) |