作为Clojure的新手,我经常很难表达最简单的东西。例如,要替换向量中的最后一个元素,将是
v[-1]=new_value
在python中,我最终在Clojure中使用以下变体:
(assoc v (dec (count v)) new_value)
至少可以说这很长而且毫无表情,或者
(conj (vec (butlast v)) new_value)
更糟糕的是,它具有
O(n)
运行时间。这让我感到很傻,就像一个穴居人试图用俱乐部修理瑞士表一样。
Clojure替换向量中最后一个元素的正确方法是什么?
为了支持我的
O(n)
-version(Clojure 1.8)的butlast
-claim:(def v (vec (range 1e6)))
#'user/v
user=> (time (first (conj (vec (butlast v)) 55)))
"Elapsed time: 232.686159 msecs"
0
(def v (vec (range 1e7)))
#'user/v
user=> (time (first (conj (vec (butlast v)) 55)))
"Elapsed time: 2423.828127 msecs"
0
因此,基本上10倍的元素数量要慢10倍。
最佳答案
我会用
(defn set-top [coll x]
(conj (pop coll) x))
例如,
(set-top [1 2 3] :a)
=> [1 2 :a]
但它也适用于列表的最前面:
(set-top '(1 2 3) :a)
=> (:a 2 3)
Clojure堆栈函数
peek
,pop
和conj
-在顺序集合的自然开放端工作。但是,没有一种正确的方法。
各种解决方案如何对空向量作出 react ?
v[-1]=new_value
会引发异常,您的(assoc v (dec (count v)) new_value)
和我的(defn set-top [coll x] (conj (pop coll) x))
也会引发异常。 (conj (vec (butlast v)) new_value)
返回[new_value]
。 butlast
无效。