2010-02-24 11 views
12

dado:¿Cómo puedo actualizar un elemento vectorial en Clojure?

(def my-vec [{:id 0 :a "foo" :b "bar"} {:id 1 :a "baz" :b "spam"} 
      {:id 2 :a "qux" :b "fred"}]) 

¿Cómo puedo actualizar idiomáticamente * el artículo en mi-vec con :id=1 que tienen valores :a="baz2" y :b="spam2"?

*: Reconozco que en realidad no actualizaría my-vec, pero realmente devolvería un nuevo vector que es idéntico a my-vec a excepción de los valores de reemplazo.

Respuesta

8

mapa una función sobre el vector de mapas que, o bien crea un mapa modificado si los partidos clave o utiliza el original si las claves no coinciden, a su vez el resultado de nuevo en un vector

(vec (map #(if (= (:id %) 1) 
      (assoc % :a "baz2" :b "spam2") 
      %))) 

Se Es posible hacer esto de manera más sucinta, aunque esta muestra realmente dónde se produce el intercambio estructural.

+0

¿El uso de la sintaxis de la función # (%) lo hace menos claro? –

10

¿Sabe de antemano que el mapa con id == 1 es el segundo mapa en su vector? Si es así:

user> (-> my-vec 
      (assoc-in [1 :a] "baz2") 
      (assoc-in [1 :b] "spam2")) 
[{:id 0, :a "foo", :b "bar"} {:id 1, :a "baz2", :b "spam2"} {:id 2, :a "qux", :b "fred"}] 

Si necesita acceder a sus datos por id mucho, otra idea es reemplazar su vector de hash mapas con un hash-mapa de hash mapas enchavetado en :id. Entonces puede más fácilmente assoc-in sin importar el orden de las cosas.

user> (def new-my-vec (zipmap (map :id my-vec) my-vec)) 
#'user/new-my-vec 
user> new-my-vec 
{2 {:id 2, :a "qux", :b "fred"}, 1 {:id 1, :a "baz", :b "spam"}, 0 {:id 0, :a "foo", :b "bar"}} 
user> (-> new-my-vec 
      (assoc-in [1 :a] "baz2") 
      (assoc-in [1 :b] "spam2")) 
{2 {:id 2, :a "qux", :b "fred"}, 1 {:id 1, :a "baz2", :b "spam2"}, 0 {:id 0, :a "foo", :b "bar"}} 
+0

Hmm. Lo guardo en un vector porque lo que realmente tengo son ImageIcons de naipes y la posición del vector termina actuando como un orden z cuando dibujo. [{: id "8H": image ImageIcon} ...]. Pero podría ser capaz de almacenarlos en un mapa {{: id "8H": orden z 2: imagen ImageIcon} ...} y luego Graphics.draw ellos tirando de ellos por su orden: z-order. Gracias, Brian, eres un monstruo de Clojure. :) – scrotty

+4

'(update-in my-vec [1] assoc: a" baz2 ": b" spam2 ")' parece mucho más limpio. – amalloy

3

posible que desee echar un vistazo a array-map que crea un mapa respaldado por una matriz y tecleado por el índice en lugar de utilizar: id?

Cuestiones relacionadas