使用列表或向量,我的Clojure功能可能会非常慢吗?

Avi*_*lax 4 performance clojure data-structures

我刚刚学习Clojure,我刚刚编写了这个函数:

(defn replace-last [coll value]
    (assoc coll (dec (count coll)) value))
Run Code Online (Sandbox Code Playgroud)

我只是有点担心它对于列表和/或向量来说可能真的很慢 - 我只是不了解它们还不知道.

谢谢!

Mic*_*zyk 11

对于向量,这将非常快 - 向量的一个承诺是快速创建略微修改的副本.

对于列表,这根本不起作用 - 它们不是associative(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])))
Run Code Online (Sandbox Code Playgroud)

这会延迟更换最终元素,直到你实际接近消耗你的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)
()
Run Code Online (Sandbox Code Playgroud)

  • 我认为`butlast`应该被认为是弃用的.`clojure.core`还包含`drop-last`,除了懒惰之外,它还具有能够从seq中删除任意数量元素的优点,而不仅仅是一个. (2认同)