【发布时间】:2012-01-16 21:40:55
【问题描述】:
我刚学Clojure,刚写了这个函数:
(defn replace-last [coll value]
(assoc coll (dec (count coll)) value))
我只是有点担心它对于列表和/或向量来说可能真的很慢——我只是对它们还不够了解。
谢谢!
【问题讨论】:
标签: performance data-structures clojure
我刚学Clojure,刚写了这个函数:
(defn replace-last [coll value]
(assoc coll (dec (count coll)) value))
我只是有点担心它对于列表和/或向量来说可能真的很慢——我只是对它们还不够了解。
谢谢!
【问题讨论】:
标签: performance data-structures clojure
对于向量,这将非常快——向量的承诺之一是快速创建稍微修改的副本。
对于列表,这根本不起作用——它们不是关联的 (clojure.lang.Associative),因此不是 assoc 的有效参数。至于其他可能的方法,如果您需要返回一个实际的列表(而不是一个 seq(able)),那么您就不走运了——访问/替换列表的最后一个元素基本上是一个线性时间操作。另一方面,如果您可以使用除了最后一个元素之外看起来像您的列表的惰性序列,您可以实现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 中删除任意数量的元素,而不仅仅是一个。
drop-last。谢谢!
这对于向量来说和其他任何东西一样快,但对于列表根本不起作用。
【讨论】: