clojure:弹出和推送
clojure: pop and 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)
pop-and-push 可以这样实现:
(defn pop-and-push [coll x]
(concat (pop coll) ["x"]))
(不幸的是,这不适用于由例如 range 生成的序列,它只会在传递由文字 '(..) 声明的序列时弹出。)
但这是最优的吗?
这里的主要问题(一旦我们将 "x"
更改为 x
)是 concat
returns a lazy-seq
,并且惰性序列无效参数为 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]
如你所见,这个版本其实可以自己操作return值
如评论中所述,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 "clojure.lang.PersistentQueue@7c42"]
user=> (into [] *1)
[2 3 4]
user=> (pop-and-push *2 5)
#object[clojure.lang.PersistentQueue 0x4bd31064 "clojure.lang.PersistentQueue@8023"]
user=> (into [] *1)
[3 4 5]
PersistentQueue 数据结构,虽然在某些方面使用起来不太方便,但实际上针对这种用法进行了优化。
我正在寻找一个非常适合以下操作的顺序数据结构。列表的长度保持不变,它永远不会长于或短于固定长度。
省略第一项并在末尾添加 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)
pop-and-push 可以这样实现:
(defn pop-and-push [coll x]
(concat (pop coll) ["x"]))
(不幸的是,这不适用于由例如 range 生成的序列,它只会在传递由文字 '(..) 声明的序列时弹出。)
但这是最优的吗?
这里的主要问题(一旦我们将 "x"
更改为 x
)是 concat
returns a lazy-seq
,并且惰性序列无效参数为 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]
如你所见,这个版本其实可以自己操作return值
如评论中所述,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 "clojure.lang.PersistentQueue@7c42"]
user=> (into [] *1)
[2 3 4]
user=> (pop-and-push *2 5)
#object[clojure.lang.PersistentQueue 0x4bd31064 "clojure.lang.PersistentQueue@8023"]
user=> (into [] *1)
[3 4 5]
PersistentQueue 数据结构,虽然在某些方面使用起来不太方便,但实际上针对这种用法进行了优化。