Can my Clojure function be very slow with lists or vectors?

I am just learning Clojure and I just wrote this function:

(defn replace-last [coll value] (assoc coll (dec (count coll)) value)) 

I'm just a little worried that it can be very slow for lists and / or vectors. I just do not understand them enough to know.

Thanks!

+4
source share
2 answers

For vectors, this will be pretty fast - one of the promises vectors is the quick creation of slightly modified copies.

For lists, this will not work at all - they are not associative ( clojure.lang.Associative ) and therefore are not valid arguments for assoc . As for the other possible approaches, if you need to get the actual list back (unlike seq (maybe)), you are out of luck - accessing / replacing the end element of the list is basically a linear time operation. If, on the other hand, you are fine with a lazy seq that looks like your list, with the exception of the final element, you can implement the semi-lazy version of butlast (the one in clojure.core not lazy at all) and use this with using lazy-cat :

 (defn semi-lazy-butlast [s] (cond (empty? s) s (empty? (next s)) nil ; or perhaps () :else (lazy-seq (cons (first s) (semi-lazy-butlast (next s)))))) (defn replace-last [sx] (if (empty? s) ; do nothing if there is no last element to replace s (lazy-cat (semi-lazy-butlast s) [x]))) 

This will cancel the end element replacement until you get close to it consuming your seq.

Interaction with the sample:

 user=> (take 10 (replace-last (range) :foo)) (0 1 2 3 4 5 6 7 8 9) user=> (take 10 (replace-last (range 10) :foo)) (0 1 2 3 4 5 6 7 8 :foo) user=> (replace-last () :foo) () 
+11
source

It will be as fast as everything else for vectors, and will not work at all for lists.

+3
source

Source: https://habr.com/ru/post/1391333/


All Articles