Есть ли способ удалить элемент из вектора, основанного на индексе, на данный момент я использую subvec для разделения вектора и повторного создания его снова. Я ищу обратную связь для векторов?
Clojure Удалить элемент из вектора в указанном месте
Ответ 1
subvec
, вероятно, лучший способ. Clojure docs говорят, что subvec
- это "O (1) и очень быстро, так как результирующая структура векторных акций с оригиналом и без обрезки". Альтернативой было бы перемещение вектора и создание нового, пропуская некоторые элементы, которые будут медленнее.
Удаление элементов из середины вектора не является чем-то необходимым для векторов. Если вам нужно делать это часто, подумайте об использовании хэш-карты, чтобы вы могли использовать dissoc
.
См:
Ответ 2
(defn vec-remove
"remove elem in coll"
[coll pos]
(vec (concat (subvec coll 0 pos) (subvec coll (inc pos)))))
Ответ 3
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"
Yup - subvec самый быстрый
Ответ 4
Вот решение 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)
Ответ 5
В векторной библиотеке clojure.core.rrb-vector
предоставляется логарифмическая конкатенация и нарезка времени. Предполагая, что вам нужна настойчивость, и учитывая то, о чем вы просите, логарифмическое временное решение так же быстро, как теоретически возможно. В частности, это намного быстрее, чем любое решение с использованием clojure native 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]
Ответ 6
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
.
Ответ 7
Еще одна возможность, которая должна работать с любой последовательностью и не бомбить, если индекс был вне допустимого диапазона...
(defn drop-index [col idx]
(filter identity (map-indexed #(if (not= %1 idx) %2) col)))