2016-02-13 40 views
1

我正在寻找一个连续的数据结构,这是完美的下面的操作。名单的长度保持不变,永远不会长于或短于固定长度。Clojure的:pop和push

省略第一个项目,并添加X到底。

(0 1 2 3 4 5 6 7 8 9) 

(pop-and-push "10") 

(1 2 3 4 5 6 7 8 9 10) 

有一个必须同样经常做只有一个其他阅读操作:

(last coll) 

弹出式和推可以实现这样的:

(defn pop-and-push [coll x] 
    (concat (pop coll) ["x"])) 

(不幸的是,这并不与由例如范围产生序列工作,当..)由文字“(声明的序列传递它只是弹出。)

但是这是最佳的?

+0

描述更清晰的方式''()''对比(范围n)'的问题是,pop'的'这种用法适用于名单,但没有其他集合类型(有各种不正确的行为的lazy- seqs,向量,集合,数组,字符串等等,从明确的错误到刚刚得到错误的输出而没有检测到错误)。 – noisesmith

回答

4

主要的问题在这里(一旦我们改变"x"x)是concat返回lazy-seq,和懒seqs是无效的参数传递给pop

user=> (defn pop-and-push [coll x] (concat (pop coll) [x])) 
#'user/pop-and-push 
user=> (pop-and-push [1 2 3] 4) 
(1 2 4) 
user=> (pop-and-push *1 5) 
ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IPersistentStack clojure.lang.RT.pop (RT.java:730) 

我的天真偏好是使用一个向量。这个功能很容易用subvec实现。

user=> (defn pop-and-push [v x] (conj (subvec (vec v) 1) x)) 
#'user/pop-and-push 
user=> (pop-and-push [1 2 3] 4) 
[2 3 4] 
user=> (pop-and-push *1 5) 
[3 4 5] 

,你可以看到,这个版本可以在自己的返回值,实际操作

正如评论所说,PersistentQueue是针对这种情况作出:

user=> (defn pop-and-push [v x] (conj (pop v) x)) 
#'user/pop-and-push 
user=> (pop-and-push (into clojure.lang.PersistentQueue/EMPTY [1 2 3]) 4) 
#object[clojure.lang.PersistentQueue 0x50313382 "[email protected]"] 
user=> (into [] *1) 
[2 3 4] 
user=> (pop-and-push *2 5) 
#object[clojure.lang.PersistentQueue 0x4bd31064 "[email protected]"] 
user=> (into [] *1) 
[3 4 5] 

的PersistentQueue数据结构虽然在某些方面使用起来不方便,但实际上已经为此使用进行了优化。