Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing elements of a map conditionally in Clojure

Tags:

clojure

I'm looking for the best way to conditionally avoid adding an element to a map when it is being initialized/defined. In this case, I want to avoid adding an element to a map if the value for the key is nil.

(defn create-record [data]
  (let [res {
    :username (data :username)
    :first-name (get-in data [:user-info :name :first])
    :last-name (get-in data [:user-info :name :last])
    :gender (get-in data [:user-info :sex])
   }])
)

I don't want to add gender to the map if the results of the get-in are nil (the sex field in the data does not exist). Is there a way to do this when I create the map? I could remove all keys whose value is nil after I create the map but, in some cases, I want some keys to have nil values and others to not be in the map at all if they would have nil values.

like image 811
Geoffrey Gallaway Avatar asked Jan 24 '12 19:01

Geoffrey Gallaway


3 Answers

I would use a combination of merge and when-let for these optional parameters.

The core idea is to merge in either a single element map or nil for each of the optional parameters. Merging in nil will do nothing, so you won't see the nil in the map.

(defn create-record [data]
  (let [res (merge {:username (data :username)
                    :first-name (get-in data [:user-info :name :first])
                    :last-name (get-in data [:user-info :name :last])}
                   (when-let [gender (get-in data [:user-info :sex])]
                     {:gender gender}))]
    res))

Depending on how frequently you need to do this, I would recommend writing a short macro or function around the when-let to keep the code more concise.

like image 71
deterb Avatar answered Nov 15 '22 05:11

deterb


(cond-> {:username   (data :username)
         :first-name (get-in data [:user-info :name :first])
         :last-name  (get-in data [:user-info :name :last])}
    (get-in data [:user-info :sex]) (assoc :gender (get-in data [:user-info :sex])))
like image 43
user2347796 Avatar answered Nov 15 '22 03:11

user2347796


(defn create-record [data]   
   (merge {:username   (data :username)
           :first-name (get-in data [:user-info :name :first])
           :last-name  (get-in data [:user-info :name :last])}
           (when       
             (get-in data [:user-info :sex]) 
             {:gender (get-in data [:user-info :sex])})))

Just add when for each element you want to check if it is not nil and then it will return a map to be merged or nil that will not affect the return map value.

You can merge several maps together so there is no limit of maps to merge and you can return a separate map for each element that is not nil.

like image 2
shmuel ko Avatar answered Nov 15 '22 04:11

shmuel ko