Map transformation in clojure 1/2

Here it’s another chapter of the series about clojure map.

For those who missed the previous chapter:

Let’s keep going in our journey about clojure map.

In the next chapters I am going to talk about how to modify clojure maps.

As you may know in Clojure we usually don’t “modify” anything but we rather return a new value.

Let’s explore what function clojure.core gives us to modify maps.

The easiest function to start with is definitely

assoc

Given a map, a key and a value assoc(ciate) add the key and the respective value to the map.

user> (assoc {:a 1 :b 2} :c 3)
{:c 3, :b 2, :a 1}

As you may guess assoc can take more than just a couple of :keys value.

user> (assoc {:a 1 :b 2} :c 3 :d 4)
{:d 4, :c 3, :b 2, :a 1}
user> (assoc {:a 1 :b 2} :c 3 :d 4 :e 5)
{:e 5, :d 4, :c 3, :b 2, :a 1}

It is important is that you don’t forget to provide an even number of argument after the map.

user> (assoc {:a 1 :b 2} :c 3 :d)
IllegalArgumentException assoc expects even number of arguments after map/vector, found odd number  clojure.core/assoc (core.clj:192)

You may also wonder what happens if you try to assoc to an already existing key.

user> (assoc {:a 1 :b 2} :a "new-value")
{:b 2, :a "new-value"}

As we can see assoc will reset (update) the old value to the new one.

assoc is a perfectly legitimate way to update old values in a clojure map.

If assoc will make our maps bigger

dissoc

will make them smaller.

As you may have already guessed dissoc(ciate) will remove a map entry from our maps.

It works exactly like assoc.

user> (dissoc {:a 1 :b 2 :c 3} :a)
{:c 3, :b 2}

If you pass more arguments it will remove more map entries

user> (dissoc {:a 1 :b 2 :c 3} :a :b)
{:c 3}

Also note that dissoc a not existing key is a valid behavior, dissoc will eliminate the map entry, which does not exist and will return the (not) updated map.

user> (dissoc {:a 1 :b 2 :c 3} :d :e :f)
{:c 3, :b 2, :a 1}

merge

Another very useful function is merge which, as you may have guessed, merge two or more different maps into one.

user> (merge {:a 1 :c 3} {:b 2 :d 4})
{:d 4, :b 2, :c 3, :a 1}
user> (merge {:a 1 :c 3} {:b 2 :d 4} {:foo "foo" :bar :bar})
{:foo "foo", :bar :bar, :d 4, :b 2, :c 3, :a 1}

merge is very simple to reason about, but there is a little detail to keep in mind.

What happens if there is a key collision (if we try to merge two maps with some keys in common) ?

Fortunately this case is documented and made clear in the spec.

In case of key collision the resulting element will be the later to appear.

user> (merge {:a 1} {:a 2})
{:a 2}
user> (merge {:a 1 :b 1} {:a 2 :c 2} {:c 3 :b 3})
{:c 3, :b 3, :a 2}

end

In the next chapter we are going to explore some function a little more complex, function such as update-in and merge-with.

As always stay tuned and for any question please don’t hesitate to write me or to comment bellow.

I am available for freelance work, I am specialized in IoT and distributed fault tolerant systems, if you are interested in working with me you can get in touch here: simone [at] mweb [dot] biz