David Rz Ayala
David Rz Ayala

Reputation: 2235

How to insert an if on a hash-map in clojure

This is valid:

{:a :v (if true :f) :r }

This is not

{:a :v (if true {:f :r}) }

Since it wants to put a new hashmap in the structure

I need to return in that if a special structure (that I have forgotten its name) that contains the key and value so it gets inserted in the hash map.

Thanks

Upvotes: 2

Views: 2273

Answers (3)

sw1nn
sw1nn

Reputation: 7328

Conditional threading macros are often helpful for this sort of thing. Especially if you are already using them to apply a series of transform to your data. Here's a sketch of creating http headers

(let [compressed? true
      custom-header? false]

    (-> {:content-type "text/plain"}
        (cond-> compressed? (assoc :content-encoding "gzip"))
        (cond-> custom-header? (assoc :my-custom-header "foo"))
        clojure.walk/stringify-keys))

;=> {"content-encoding" "gzip", "content-type" "text/plain"}

Upvotes: 4

jbm
jbm

Reputation: 2600

The second case fails not because the if form is returning the wrong type of value but because the map contains an odd number of items. Map literals must contain an even number of forms, and the if is a single form.

There are several ways to add things to maps in Clojure.

You can use conj with either a vector or a map argument:

(conj {:a :v} [:f :r])  ;;=> {:f :r, :a :v}
(conj {:a :v} {:f :r})  ;;=> {:f :r, :a :v}

You can use assoc with the key and val as separate arguments:

(assoc {:a :v} :f :r)   ;;=> {:f :r, :a :v}

Or you can use merge with two (or more) maps as arguments:

(merge {:a :v} {:f :r}) ;;=> {:f :r, :a :v}

The special structure you're thinking of may be a MapEntry. That's what the items are in a seq created by calling seq on a map.

For instance:

(seq a-map)                ;;=> ([:a :v] [:f :r])
(first (seq a-map))        ;;=> [:a :v]
(-> a-map seq first class) ;;=> clojure.lang.MapEntry

Map entries look and behave just like vectors, with one addition. You can use the key and val functions to access the key and val respectively (effectively equivalent to (get map-entry 0) and (get map-entry 1)).

(key map-entry) ;;=> :a
(val map-entry) ;;=> :v

You can conj a map entry onto a map just like you can a vector.

Upvotes: 4

leontalbot
leontalbot

Reputation: 2543

Is this what you need?

(merge {:a :v} (if true {:f :r}))
=> {:f :r, :a :v}

Upvotes: 3

Related Questions