Подтвердить что ты не робот

Clojure Удалить элемент из вектора в указанном месте

Есть ли способ удалить элемент из вектора, основанного на индексе, на данный момент я использую subvec для разделения вектора и повторного создания его снова. Я ищу обратную связь для векторов?

4b9b3361

Ответ 1

subvec, вероятно, лучший способ. Clojure docs говорят, что subvec - это "O (1) и очень быстро, так как результирующая структура векторных акций с оригиналом и без обрезки". Альтернативой было бы перемещение вектора и создание нового, пропуская некоторые элементы, которые будут медленнее.

Удаление элементов из середины вектора не является чем-то необходимым для векторов. Если вам нужно делать это часто, подумайте об использовании хэш-карты, чтобы вы могли использовать dissoc.

См:

  • subvec в clojuredocs.org
  • subvec в clojure.github.io, на котором указывает официальный сайт.

Ответ 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)))