Для векторов это будет довольно быстро - одно из обещаний векторов - быстрое создание слегка модифицированных копий.
Для списков это не будет работать вообще - они не являются ассоциативными (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])))
Это задерживает заменив последний элемент, пока вы на самом деле не приблизиться к ней в потреблении вашего SEQ.
Образец взаимодействия:
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)
()
Великий ответ, спасибо! –
Я думаю, что 'butlast' следует считать устаревшим. 'clojure.core' также содержит' drop-last', который, помимо лени, имеет то преимущество, что может удалить любое количество элементов из seq, а не только из одного. –
@ DanielJanus: Ого, я полностью пропустил 'drop-last'. Благодаря! –