The assoc that makes a vector grow

For those using a RSS reader, subscribe here: rss.xml

Vectors are quite interesting in clojure, in particular when you combine them with the assoc operation. The docs for the assoc function says: “When applied to a vector, returns a new vector that contains val at index. Note - index must be <= (count vector)”. Notice how it does not say that the index must be strictly less than the count of the vector, but less or equal to it. That means that the returned vector can be one larger than the original vector.

The main usecase is to update existing values or to set a next value. That is the limit, skipping more indices does throw an IndexOutOfBounds exception. As soon as you do that though, a map/dictionary/associative array makes more sense anyway. But we can still mess around with this assoc on vectors, and implement some other primitives.

The first thing we can implement is the conj function. It is an assoc with the count of the current vector, they have the same effect.

(conj [1 2] 3) ;; => [1 2 3]
(assoc [1 2] (count [1 2]) 3) ;; => [1 2 3]

And as soon as you implement conj for a single element, you can also implement it for multiple elements. Just doing it right after each other works, a reduce with the indices grows the vector one element at a time. Each of the elements will have the intented index along with it, as the assoc requires an index.

(->> [[0 10] [1 20] [2 30] [3 40] [4 50]]
     (reduce (fn [xs [i v]] (assoc xs i v)) []))
;; => [10 20 30 40 50]

From here it is a small step to implement concat. Instead of the empty vector to start the reduce, use the first list and iterate over the second list to be concatenated. All of the indices used to assoc need to be incremented, as the elements will be placed after the first list. A small detail is that it returns a vector, as at every point it remains a vector.

(concat [10 20 30] [40 50 60])
;; => (10 20 30 40 50 60)

(->> [40 50 60]
     (map vector (map #(+ % (count [10 20 30])) [0 1 2]))
     (reduce (fn [xs [i v]] (assoc xs i v)) [10 20 30]))
;; => [10 20 30 40 50 60]