Pavel Polívka

Posted on

Learning Clojure Part 3: Data Structures

In part three of our Clojure learning journey, we will go over Data Structures.

Out of the box, Clojure has a lot of structures that we will need most of the times. All of them are immutable. That means you cannot change them in place.

Data types

Clojure has great support for numerical values. It can support integers, floats, rotios, etc...

``````42
4.2
4/2
``````

Strings are represented by double-quotes. And only by them. Single quotes will not be considered strings.

``````"Darth Vader"
"\"You shall not pass\""
``````

Maps

Maps are similar to Maps in Java, Dictionaries in Python, etc..

An empty map would be defined like this:

``````{}
``````

Values would be defined like so:

``````{:title "Darth" :name "Vader"}
``````

The `:title` and `:name` are keywords. They are primarily used as keys in maps. But can be used as functions to lookup the value.

``````(:title {:title "Darth" :name "Vader"})
;=> "Darth"
``````

You can provide default value here.

``````(:place {:title "Darth" :name "Vader"} "Death Star")
;=> "Death Star"
``````

You can use strings as keys if needed tho.

Here we use a string key with the plus function.

``````{"key" +}
``````

To get this value you can use `get` function.

``````(get {"a" 0 "b" 1} "a")
;=> 0
``````

Maps can be nested:

``````{:name {:first "Anakin" :last "Skywalker"}}
``````

To get values in those you can use `get-in` expression.

``````(get-in {:name {:first "Anakin" :last "Skywalker"}} [:name :last])
;=> "Skywalker"
``````

You can also use the `hash-map` function to create a map.

``````(hash-map :a 0 :b 1)
;=> {:b 1, :a 0}
``````

Vectors

Vectors are similar to arrays. It's a 0-indexer collection.

The literal for vectors is:

``````[42 43 44]
``````

We can use get function to retrieve values:

``````(get [42 43 44] 0)
;=> 42

(get ["vector" "of" "strings"] 1)
;=> "of"
``````

We can also use `vector` expression to init a vector.

``````(vector 1 2 3 4 5)
``````

And use `conj` to add elements at the end of the vector.

``````(conj [1 2 3] 4)
;=> [1 2 3 4]
``````

Lists

Lists are very similar to vectors, there are some differences tho. You cannot retrieve an element from a list using `get` but `nth` (slower as it will go over all the elements) and `conj` add at the beginning of the collection.

``````'(1 2 3 4)
;=> (1 2 3 4)

(nth '(1 2 3 4) 0)
;=> 1

(conj '(1 2 3 4) 5)
;=> (5 1 2 3 4)
``````

So when we should use what? The best rule we can find is that when we want to easily add to the beginning we should use a list.

Sets

Sets are collections of unique values. We can use literals or a `hash-set` functions.

``````#{"Darth Vader" "Yoda" "Anakin Skywalker"}

(hash-set "Darth Vader" "Yoda" "Anakin Skywalker" "Yoda")
;=> #{"Anakin Skywalker" "Yoda" "Darth Vader"}
``````

See above that when we have multiple instances of one value, the second one is automatically removed.

We can add values to set by `conj`, when duplicated value is added it will not be.

``````(conj #{"a" "b"} "c")
;=> #{"a" "b" "c"}

(conj #{"a" "b" "c"} "c")
;=> #{"a" "b" "c"}
``````

We can also convert vectors or lists to sets by using the `set` function.

``````(set [1 1 2 2 3 3 4 4])
;=> #{1 4 3 2}
``````

We can use `contains?` to check whenever the set has the value.

``````(contains? #{1 2} 1)
;=> true

(contains? #{1 2} 3)
;=> false
``````

And we can use `get` to get a value.

``````(get #{1 2} 1)
;=> 1

(get #{1 2} 3)
;=> nil
``````

You can follow me on Twitter to get more content like this.