Learning Clojure Part 3: Data Structures
Tags: clojure, tutorial
Published: 2021-01-06 09:15:05

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...
```clojure
42
4.2
4/2
```
Strings are represented by double-quotes. And only by them. Single quotes will not be considered strings.
```clojure
"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:
```clojure
{}
```

Values would be defined like so:
```clojure
{: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.
```clojure
(:title {:title "Darth" :name "Vader"})
;=> "Darth"
```

You can provide default value here. 
```clojure
(: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.
```clojure
{"key" +}
```

To get this value you can use `get` function.
```clojure
(get {"a" 0 "b" 1} "a")
;=> 0
```

Maps can be nested:
```clojure
{:name {:first "Anakin" :last "Skywalker"}}
```

To get values in those you can use `get-in` expression.
```clojure
(get-in {:name {:first "Anakin" :last "Skywalker"}} [:name :last])
;=> "Skywalker"
```

You can also use the `hash-map` function to create a map. 
```clojure
(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:
```clojure
[42 43 44]
```

We can use get function to retrieve values:
```clojure
(get [42 43 44] 0)
;=> 42

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

We can also use `vector` expression to init a vector. 
```clojure
(vector 1 2 3 4 5)
```

And use `conj` to add elements at the end of the vector. 
```clojure
(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.
```clojure
'(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.
```clojure
#{"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. 
```clojure
(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. 
```clojure
(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.
```clojure
(contains? #{1 2} 1)
;=> true

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

And we can use `get` to get a value. 
```clojure
(get #{1 2} 1)
;=> 1

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

---

You can follow me on [Twitter](https://twitter.com/pavel_polivka) to get more content like this.