2016-02-13 81 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數據結構雖然在某些方面使用起來不方便,但實際上已經爲此使用進行了優化。