DEV Community

Cover image for Learning Clojure, part VI
Камило Куньа
Камило Куньа

Posted on • Edited on

Learning Clojure, part VI

We already learned how to use lists and the importance of this data structure in Clojure in the previous post. Now we gonna learn another important data structure: Vector.

What are vectors?

Vectors as lists are immutable persistent data collections that can hold any value. They can be created using the vec function passing a collection of values or passing the values directly between square brackets.

;; (vec collection)
(vec '("Red" "Green" "Blue"))
;; returns => ["Red" "Green" "Blue"]

["Gold" "Silver" "Crystal"]
;; returns => ["Gold" "Silver" "Crystal"]
Enter fullscreen mode Exit fullscreen mode

Vectors vs Lists

Both vectors and lists are collections of data, but they differ a lot in how each one of them works. The first main difference you probably notice between them is while lists are written using parenthesis, vectors are written using square brackets.

'("List" 1 2 3)
;; returns => ("List" 1 2 3)

["Vector" 1 2 3]
;; returns => ["Vector" 1 2 3]
Enter fullscreen mode Exit fullscreen mode

Looking now they seem to do the same thing, but the data structure underlying these collections are different and have a lot of differences in practical use.

(class '("List" 1 2 3))
;; returns => clojure.lang.PersistentList

["Vector" 1 2 3]
;; returns => clojure.lang.PersistentVector
Enter fullscreen mode Exit fullscreen mode

While lists, as we seem, are noncontinuous values in memory that hold a value and a reference to the next value, vectors are values that are continuous in memory so the elements are indexed and can be fast accessed by their index position using the function nth.

;; (nth collection index)

(nth ["Charmander" "Pikachu" "Buterfree"] 0)
;; returns => "Charmander"

(nth ["Charmander" "Pikachu" "Buterfree"] 2)
;; returns => "Buterfree"
Enter fullscreen mode Exit fullscreen mode

The image shows a vector with five strings represented as a continuous tape with each index pointing to the segment where the next value beggins

Image: "Vectors representation" made by the author is copyleft material under unlicense.

Adding values

Another great difference between them is when we use the conj function to add an element to the collection because the function will add the element in faster way to the collection:

  • In lists is faster to add a new element to the beginning since that to do it it's not necessary to go through the entire list to add it in another position.
  • In vectors, the element is added in the last position since it just gets the last index and adds it after.

The image represent the conj function and each square is a different value, when an element is added in a list it is added in beginning and when an element is added in a vector it is added in the last

Image: "Conj vector vs list" made by the author is copyleft material under unlicense.

We can see this with some examples:

(conj  '("Charmander" "Pikachu" "Buterfree") "Zubat")
;; returns => ("Zubat" "Charmander" "Pikachu" "Buterfree")

(conj  ["Charmander" "Pikachu" "Buterfree"] "Zubat")
;; returns => ["Charmander" "Pikachu" "Buterfree" "Zubat"]
Enter fullscreen mode Exit fullscreen mode

Vectors and Lists

We can use the nth to efficiently access a value by its position, but we can also use any of the functions we see in lists before as well. They can be used to iterate over the vector as we can do with lists and other collections.

first

The first function returns the element at the beginning of the vector.

(first ["Brock" "Misty" "Lt. Surge" "Erika"])
;; returns => "Brock"
Enter fullscreen mode Exit fullscreen mode

second

The second function returns the second element of the vector.

(second ["Brock" "Misty" "Lt. Surge" "Erika"])
;; returns => "Misty"
Enter fullscreen mode Exit fullscreen mode

last

The last function returns the element at the end of the vector.

(last ["Brock" "Misty" "Lt. Surge" "Erika"])
;; returns => "Erika"
Enter fullscreen mode Exit fullscreen mode

rest

The rest functions return the vector as a list without the first element.

(rest ["Brock" "Misty" "Lt. Surge" "Erika"])
;; returns => ("Misty" "Lt. Surge" "Erika")
Enter fullscreen mode Exit fullscreen mode

When we should use lists over vectors?

If you intend to add and retrieve values at the beginning or at the end of the collection all the time, then a list will be far more efficient than a vector.

On another side, if you need to add and retrieve values in the middle or in indexed positions then a vector will be far more efficient than a list.

You should consider it when choosing which of them you will use, as general advice usually vectors are more frequently used than lists in most cases.

See you in the next part!

Having 2 different collections that look so similar and work so different can be a little confusing at begging especially if you don't know how these data structures are made but don't worry this will become natural as you get used to Clojure.

Top comments (0)