Hendekagon
Hendekagon

Reputation: 4643

Progressive association in Clojure

I came across a thing I needed today where I wanted to progressively associate entries in a map, each based on the results of the previous one(s). Here's what I did:

(defn -Y [v k f] (assoc v k (f v)))

(defn build-map [a-map]
 (-> a-map
  (-Y :x #(reduce + (:values %) )  )
  (-Y :y #(/ (:x %) 100) )
  (-Y :z #(* (:y %) 10000000) )
 )
)
(build-map {:values (range 8)})

I'd welcome your thoughts on a) is it a good thing ? b) is there an existing way to do it that I haven't seen ? (I don't know the API well)

Upvotes: 3

Views: 152

Answers (2)

Christian Berg
Christian Berg

Reputation: 14506

I think the answer by Ankur is a good improvement on your original design.

I just wanted to mention that it's not always necessary to overcomplicate things. If you compute all the additional map entries in the same function anyways, this simple approach is much more readable, in my opinion:

(defn build-map [a-map]
  (let [x (reduce + (:values a-map))
        y (/ x 100)
        z (* y 10000000)]
    (merge a-map {:x x :y y :z z})))

Upvotes: 10

Ankur
Ankur

Reputation: 33657

So you got a map that goes through some transformations and you end up with a final map. Your implementation looks fine to me except that -Y isn't doing much of thing and it may not be required as a separate function.

You can do all this using just reduce function, something like:

(def operations [ [:x #(reduce + (:values %))]    
                  [:y #(/ (:x %) 100)]      
                  [:z #(* (:y %) 10000000)]    
                ])

(defn build-map [a-map]
   (reduce (fn [s [k f]] (assoc s k (f s) ) ) a-map operations)
   )

(build-map {:values (range 8)})

Upvotes: 7

Related Questions