2
votes

Suppose I have a map:

{:name "foo"
 :age "bar"}

And another one

{:name (fn [val] (println val))
 :age (fn [val] (= val "bar"))}

I want to apply function keyed by :name on second map to the first map, which also keyed by :name and the function keyed by :age to the first map which keyed by :age. How to do this the clojure way?

4

4 Answers

7
votes

You can use merge-with

(def m1 {:name "foo"
         :age "bar"})

(def m2 {:name (fn [val] (println val))
         :age (fn [val] (= val "bar"))})

user=> (merge-with #(%1 %2) m2 m1)
foo
{:name nil, :age true}
1
votes

map over one map and get corresponding function from the other one.

(def m1 {:name "foo"
         :age "bar"})

(def m2 {:name (fn [val] (println val))
         :age (fn [val] (= val "bar"))})

(map (fn [[k v]]
       ((get m2 k) v)) 
     m1)

Each iteration over the map passes a vector to the function, in your sample:

[:name "foo"]
[:age "bar"]

So destructuring the function parameter into [[k v]] gives you each key/value separately.

1
votes
(def data { :name "don knotts" 
        :dob "1/1/1940" 
        :cob "Valdosta"  })

(def fxns {:name identity :dob identity :cob clojure.string/reverse})

(defn bmap [data fxn]
  (apply merge (for [[k1 d] data [k2 f] fxn  :when (= k1 k2)]
     {k1 (f d)})))

;=user>{:cob "atsodlaV", :dob "1/1/1940", :name "don knotts"}
0
votes

I like this, if you need more resilience:

(defn fmm [m fm]
  (let [f (fn [k] ((get fm k identity) (k m)))
        ks (keys m)]
    (zipmap ks (map f ks))))