nha
nha

Reputation: 18005

Clojure apply transform function to values of a map

Let's say I have a map :

 {:top 2.8421709430404007E-14, :left 0, :down 240, :right 400N}

How can I iterate over it to convert everything into integers ?

 {:top 0, :left 0, :down 240, :right 400}

An obvious solution would be :

 {:top (:top m), :left (:left m), :down (:down m), :right (:right m)}

but it feels very repetitive.

I feel a reducing function could do nicely here, but I'm not sure how.

Upvotes: 1

Views: 631

Answers (2)

jas
jas

Reputation: 10865

Doing a map over the entries could be another way:

(into {} (map (fn [[k v]] [k (int v)]) m))
;; {:top 0, :left 0, :down 240, :right 400}

Upvotes: 3

nha
nha

Reputation: 18005

I had to use reduce-kv:

(reduce-kv #(assoc %1 %2 (int %3)) {} {:top 2.8421709430404007E-14, :left 0, :down 240, :right 400N})
;;=>{:down 240, :left 0, :right 400, :top 0}

Edit : algo.generic.fmap looks like it would work as well.

Edit bis : Thanks to @Andre for mentioning that a map-vals function exists in both weavejester/medley or prismatic/plumbing.

From medley :

(defn map-vals
  "Maps a function over the values of an associative collection."
  [f coll]
  (reduce-map (fn [xf] (fn [m k v] (xf m k (f v)))) coll))

From plumbing :

(defn map-vals
  "Build map k -> (f v) for [k v] in map, preserving the initial type"
  [f m]
  (cond
   (sorted? m)
   (reduce-kv (fn [out-m k v] (assoc out-m k (f v))) (sorted-map) m)
   (map? m)
   (persistent! (reduce-kv (fn [out-m k v] (assoc! out-m k (f v))) (transient {}) m))
   :else
   (for-map [[k v] m] k (f v))))

Upvotes: 2

Related Questions