In this article, we present an interesting function named
Let’s say, you want to log events but you don’t want to limit the memory consumption. Let’s say you want to store the 1000 last events of your system.
In clojure, it’s really easy to achieve that:
- you initialize a vector of size 1000 (e.g 1000 times
- on each
append, you remove the first (the oldest) element
Let’s see it in action with KLIPSE:
(defn append-cyclic[lst a] (concat (rest lst) [a])) (-> (repeat 3 nil) (append-cyclic 9) (append-cyclic 10) (append-cyclic 11) (append-cyclic 12))
On each call to
append-cyclic, the first element of the vector is removed and the new element is appended at the end of the vector.
Now, let’s improve our code from a performace perspective, by using a FIFO queue -
PersistentQueue - instead of lists, as it was suggested by Jozef Wagner.
(defn queue [size] (into (PersistentQueue.) (repeat size nil))) (defn append-cyclic-queue [queue x] (pop (conj queue x))) (-> (queue 3) (append-cyclic-queue 9) (append-cyclic-queue 10) (append-cyclic-queue 11) (append-cyclic-queue 12))
(defn run [q iterations func] (loop [n 0 q q] (if (< n iterations) (recur (inc n) (func q n)) q))) (with-out-str (time (run (queue 100) 1000 append-cyclic-queue)))
(with-out-str (time (run (queue 100) 1000 append-cyclic)))
You see that the queue based approach is much must faster.
Clojure vs. Clojurescript
Almost, all the code presented here is portable between
clojurescript, except the code for the queue creation.
If you want to use the queue based implementation in
clojure, you have to create the queue with a slighlty diffent syntax: