Clojure’s collections (11/09/2020)

Languages > Clojure

Generalities

Collections are immutable compound values. There are 4 types of them: Vectors, lists, sets and maps.

[1 2 3]  ;Vector
'(1 2 3)  ;List
#{1 2 3}  ;Set
{:a 1, :b 2}  ;Map

Count

All Clojure’s collections can be counted:

(count [1 2 3])  ;Will return 3.
(count '(1 2 3))  ;Will return 3.
(count #{1 3 4})  ;Will return 3.
(count {:a 1, :b 2}  ;Will return 2.

Into

The ‘into’ function return a new collection of the type of its first argument containing the elements of its both arguments.

(into [1 2 3] '(4 5 6))  ;Will return [1 2 3 4 5 6].

Vectors

Vectors are sequential and indexed from 0. New elements are always added at the tail.

[1 2 3]  ;A vector.
(vector 1 2 3)  ;The 'vector' function construct a vector with its arguments.
(def v [1 2 3])  ;A vector can be bind to a symbol.
(get v 0)  ;The 'get' function return the value at the given index.
(get v 10)  ;Trying to access an non existing index will return 'nil'.
(conj v 4 5 6)  ;The 'conj' function will return a new vector [1 2 3 4 5 6].

Lists

Lists are sequential and non indexed. New elements are always added at the head.

'(1 3 3)  ;A list must be prefixed by ' to avoid evaluation as a function call.
(def l '(1 2 3))  ;A list can be bind to a symbol.
(first l)  ;The 'first' function return the first element of the list.
(rest l)  ;The 'rest' function return the list without its first element.
(conj l 4 5 6)  ;The 'conj' function will return a new list (6 5 4 1 2 3).

Sets

Sets are unordered and with no duplicates.

#{1 2 3}  ;A set.
(def s #{1 2 3})  ;A set can be bind to a symbol.
(def s2 (conj s 4 5 6))  ;The 'conj' function will return a new set containing 1, 2, 3, 4, 5 and 6.
(disj s2 1 3 5)  ;The 'disj' function will return a new set containing 2, 4 and 6.
(contains? s 3)  ;The 'contains?' function return true if the given element exist in the set, false otherwise.
(conj (sorted-set) 3 1 2)  ;

Sorted sets

(def s (sorted-set 1 2 3))  ;The 'sorted-set' function will create the sorted set #{1 2 3}.
(conj s 4 5 6) ;All the sets created from s will be sorted. Here #{1 2 3 4 5 6}.

Maps

Maps share the sets properties but store key/value pairs.
There is a guarantee that functions acting in “sequence” will always walk a particular map instance in the same order.

{:a 1 :b 2}  ;A map.
(def m {:a 1 :b 2})  ;A map can be bind to a symbol.
(assoc m :c 3)  ;The 'assoc' function return a new map {:a 1 :b 2 :c 3}.
(assoc m :c 4)  ;If the key already exist the value is changed in the new map {:a 1 :b 2 :c 4}.
(dissoc m :b)  ;The 'dissoc' function return a new map {:a 1}.
(get m :b)  ;The 'get' function return the value associated with the given key. Here 2.
(m :b)  ;Using the map as a function is equivalent to using 'get', but will crash if the map is nil.
(get m :c 0)  ;The 'get' function can get a default, this value will be returned if the key does not exist.
(m :c 0)  ;Same thing using the map directly.
(contains? m :b)  ;The 'contains?' function return true if the given key exist in the set, false otherwise.
(find m :b) ;The 'find' function return a vector containing the key and its value. Here [:b 2].
(keys m)  ;The 'keys' function return a list of all the map's keys. Here (:a :b).
(vals m)  ;The 'vals' function return a list of all the map's values. Here (1 2).
(zipmap [:a :b] [1 2])  ;The 'zipmap' function return a new map {:a 1 :b 2}.
(merge m {:c 3 :d 4})  ;The 'merge' function return a new map {:a 1 :b 2 :c 3 :d 4}.
(merge m {:b 1})  ;In case of conflict the rightmost value win. Here {:a 1 :b 1}.
(merge-with + m {:b 1})  ;The 'merge-with' function use the given function in case of conflict. Here {:a 1 :b 3}.

Sorted maps

Maps are sorted by keys.

(def m (sorted-map :b 1 :a 2))  ;The 'sorted-map' function will create the sorted map {:a 2 :b 1}.
(assoc m :c 3) ;All the maps created from m will be sorted. Here {:a 2 :b 1 :c 3}.

Using maps as “C structs”

(def Master
 {:firstName "Blaise"
  :lastName "Ebuth"
  :age 666
  :occupation "World domination"
  :address 
   {:street "1 Highway to Hell"
    :city "Hell-City"
    :state "Hell"}})  ;Collections can be nested.
(:age Master "Unknown")  ;Keys can also be used as functions and take a default return value.
(get-in Master [:address :street])  ;The 'get-in' function allow access to nested maps via a "key path".
(assoc-in Master [:address :street] "2 Highway to Hell")  ;Return a new map with the updated value.
(update-in Master [:address :state] 
 clojure.string/upper-case)  ;Return a new map with the value update by the given function. Can take more args.

Records

However records are specially designed for this use and can be used to define multiple similar “structs”. They can be used exactly like maps excepted that they can’t be invoked as functions.

(defrecord Person [firstName lastName age])  ;Define a new record structure with the listed fields.
(def Master (->Person "Blaise" "Ebuth" 666))  ;{:firstName "Blaise", :lastName "Ebuth", :age 26}

Something to say ?

Leave a Reply

Your email address will not be published.