Для векторов это будет довольно быстро - одно из обещаний векторов - быстрое создание слегка модифицированных копий.
Для списков это не будет работать вообще - они не ассоциативны (clojure.lang.Associative
) и, следовательно, не являются допустимыми аргументами для assoc
. Что касается других возможных подходов, если вам нужно вернуть реальный список (в отличие от seq (способного)), вам не повезло - доступ / замена последнего элемента списка по сути является линейной операцией времени. Если, с другой стороны, вы будете в порядке с ленивым seq, который будет выглядеть как ваш список, за исключением последнего элемента, вы можете реализовать полуленивый вариант butlast
(тот, что в clojure.core
, не ленивый и используйте это с 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 [s x]
(if (empty? s) ; do nothing if there is no last element to replace
s
(lazy-cat (semi-lazy-butlast s) [x])))
Это откладывает замену последнего элемента до тех пор, пока вы фактически не приблизитесь к нему в использовании своей последовательности.
Пример взаимодействия:
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)
()