Clojure 从指定位置的 Vector 中删除项目

问题描述 投票:0回答:9

有没有办法根据索引从向量中删除项目,目前我正在使用 subvec 来分割向量并再次重新创建它。我正在寻找向量的 assoc 的反面?

vector clojure
9个回答
35
投票

subvec
可能是最好的方法。 Clojure 文档说
subvec
是“O(1) 并且非常快,因为生成的向量与原始向量共享结构并且没有进行任何修剪”。另一种方法是遍历向量并构建一个新向量,同时跳过某些元素,这会更慢。

从向量中间删除元素并不是向量所擅长的。如果您必须经常这样做,请考虑使用哈希映射,这样您就可以使用

dissoc

参见:

  • subvec 位于
    clojuredocs.org
  • subvec位于
    clojure.github.io
    ,官网指向。

33
投票
(defn vec-remove
  "remove elem in coll"
  [pos coll]
  (into (subvec coll 0 pos) (subvec coll (inc pos))))

18
投票
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 是最快的


9
投票

向量库

clojure.core.rrb-vector
提供对数时间串联和切片。假设您需要持久性,并考虑您的要求,对数时间解决方案在理论上尽可能快。特别是,它比使用 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]

5
投票

这是一个我发现很好的解决方案:

(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)

4
投票

subvec
很快;与瞬态相结合,它可以提供更好的结果。

使用标准进行基准测试:

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
的同一张长凳给出的意思是:
1,368250 ms
953,565863 µs
314,387437 µs


3
投票

可能会更快得到你想要的索引。

(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"

2
投票

还有另一种可能性,它应该适用于任何序列,并且如果索引超出范围则不会爆炸......

(defn drop-index [col idx]
  (filter identity (map-indexed #(if (not= %1 idx) %2) col)))

0
投票

也许不是最快的,但也许是最惯用的?

(defn remove-n [n coll]
  (let [indexed (map-indexed vector coll)
        cleaned (remove #(= n (first %)) indexed)]
    (map second cleaned)))
© www.soinside.com 2019 - 2024. All rights reserved.