2010-12-31 9 views
6

Tengo una referencia a un vector [] que tiene mapas agregados a él. Si quiero cambiar el valor de un elemento del mapa basado en una coincidencia de predicado, ¿cuál es la forma idiomática de hacerlo?forma idiomática de actualizar mapas que coinciden con un predicado en un vector

Por ejemplo ...

[{ : id 1: nombre de "Joe"} { : id 2: nombre de "Fred"} ]

Y queremos actualizar ninguna de Identificación 2 al nombre 'Brian'.

+0

véase: http://stackoverflow.com/questions/2330281/how-can-i-update-a -vector-item-in-clojure –

Respuesta

5

Aquí hay una manera:

(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"}) 

Dependiendo de cómo espera que esos valores para cambiar, puede que prefiera algo más 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"}) 

La elección de la representación argumento (vector para los parametros de búsqueda , argumentos desenrollados para los reemplazos) en create-converter fue algo arbitrario para mí; no estoy seguro de si hay una regla para eso.

3

Otra forma es encontrar el índice del mapa que desea actualizar, a continuación, actualizar solamente ese mapa [EDIT: esto es suponiendo que sólo desea actualizar un solo elemento en el vector]:

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

(defn vecmap-assoc-pred 
    [vm pred & kvs] 
    (let [i (some (fn [[i m]] (when (pred m) i)) 
       (map-indexed vector vm))] 
    (apply update-in vm [i] assoc kvs))) 

(vecmap-assoc-pred people #(= 2 (:id %)) :name "Brian") 

para este caso particular, es probable que tenga más sentido utilizar un mapa de la gente, introducido por id:

(def people {1 {:id 1 :name "Joe"} 2 {:id 2 :name "Fred"}}) 
(assoc-in people [2 :name] "Brian") 
Cuestiones relacionadas