2012-01-16 1 views
4

Я только учусь Clojure, и я просто написал эту функцию:Является ли моя функция Clojure очень медленной со списками или векторами?

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

Я просто немного обеспокоен тем, что это, вероятно, будет очень медленно либо для списков и/или векторы - я просто не понимаю, их достаточно, чтобы знать.

Спасибо!

ответ

11

Для векторов это будет довольно быстро - одно из обещаний векторов - быстрое создание слегка модифицированных копий.

Для списков это не будет работать вообще - они не являются ассоциативными (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) 
() 
+0

Великий ответ, спасибо! –

+2

Я думаю, что 'butlast' следует считать устаревшим. 'clojure.core' также содержит' drop-last', который, помимо лени, имеет то преимущество, что может удалить любое количество элементов из seq, а не только из одного. –

+0

@ DanielJanus: Ого, я полностью пропустил 'drop-last'. Благодаря! –

3

Это будет так же быстро, как и все остальное для векторов, и не будет работать вообще для списков.

Смежные вопросы