Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

idiomatic way to update maps that match a predicate in a vector

Tags:

clojure

I have a reference to a vector [] that has maps added to it. If I want to change the value of a map item based on a predicate matching, what is the idiomatic way to do that?

For example...

[ { :id 1 :name "Joe" } { :id 2 :name "Fred" } ]

And we want to update any id of 2 to the name 'Brian'.

like image 660
Sean T Allen Avatar asked Dec 31 '10 23:12

Sean T Allen


1 Answers

Here's one way:

(def people [ { :id 1 :name "Joe" } { :id 2 :name "Fred" } ])

(defn brian-converter [person] 
  (if (= 2 (:id person)) 
      (assoc person :name "Brian") 
      person))

(map brian-converter people)
;;=> ({:id 1, :name "Joe"} {:id 2, :name "Brian"})

Depending on how you expect those values to change, you might prefer something more flexible:

(defn create-converter [[key-to-match val-to-match] 
                        key-to-replace val-to-replace]
  (fn [person]
    (if (= val-to-match (key-to-match person))
        (assoc person key-to-replace val-to-replace)
        person)))

(map (create-converter [:id 2] :name "Brian") people)
;;=> ({:id 1, :name "Joe"} {:id 2, :name "Brian"})
(map (create-converter [:id 1] :name "Dude") people)
;;=> ({:id 1, :name "Dude"} {:id 2, :name "Fred"})

The choice of argument representation (vector for the search params, unrolled arguments for the replacements) in create-converter was kind of arbitrary for me; not sure if there's a rule for that.

like image 155
trptcolin Avatar answered Sep 28 '22 09:09

trptcolin