2011-08-13 11 views
16

No he encontrado mucha documentación o ejemplos de codificación para manipular vectores de mapas. Por ejemplo, si tengoVector de procesamiento de mapas en Clojure

(def student-grades 
[{:name "Billy" :test1 74 :test2 93 :test3 89} 
    {:name "Miguel" :test1 57 :test2 79 :test3 85} 
    {:name "Sandy" :test1 86 :test2 97 :test3 99} 
    {:name "Dhruv" :test1 84 :test2 89 :test3 94}]) 

y quiero agregar o asociar un nuevo par de valores clave para los promedios de prueba, que funciona debería leer sobre? Además, si alguien conoce alguna referencia/recurso para vectores de mapas en Clojure, ¡por favor comparta! ¡Muchas gracias!

Respuesta

10

En este caso, desea map una función sobre la colección (que simplemente pasa a ser un vector); para cada elemento de la colección (que resulta ser un mapa - colisión de nombres desafortunados allí), desea generar un nuevo mapa que tenga todos los pares clave-valor del mapa antiguo, más una nueva clave, digamos : avg.

p. Ej.

(into [] ; optional -- places the answer into another vector 
    (map ; apply the given function to every element in the collection 
    (fn [sg] ; the function takes a student-grade 
     (assoc sg ; and with this student-grade, creates a new mapping 
     :avg ; with an added key called :avg 
     (/ (+ (:test1 sg) (:test2 sg) (:test3 sg)) 3.0))) 
    student-grades ; and the function is applied to your student-grades vector 
)) 

ps puede utilizar (doc-fn nombre) para obtener la documentación sobre el mismo; si eres nuevo en Clojure, te aconsejo que pases un rato con los amigos de irc.freenode.net #clojure y leas un libro; mi favorito es actualmente el Programming Clojure, pero estoy esperando el próximo libro Clojure de O'Reilly con un paquete aliento.

+0

¡Muchas gracias! Estuve hurgando clojuredocs.org y no pude encontrar ejemplos relevantes para colecciones de colecciones. – Adam

+1

¡Ningún problema! Supongo que no surge como un problema, una vez que estás acostumbrado, la belleza de la programación funcional es que los bloques básicos se acumulan, por lo que cuando se trata de la colección externa, simplemente puedes tratar las colecciones internas. abstractamente, como meros elementos, y del mismo modo al escribir la función para transformar uno de estos elementos, no tiene que preocuparse por la colección externa. Lo entenderás :) –

+2

También puedes usar '(mapv ...)' como una conveniencia para '(into [] (map ...))'. – Peeja

4

Hircus ya ha proporcionado una buena respuesta, pero aquí hay otra aplicación para la comparación:

(defn average [nums] 
    (double (/ (apply + nums) (count nums)))) 

(map 
    #(assoc % :avg (average ((juxt :test1 :test2 :test3) %))) 
    student-grades) 

=> ({:avg 85.33333333333333, :name "Billy", :test1 74, :test2 93, :test3 89} etc....) 

Comentarios a tener en cuenta:

  • Por lo general vale la pena la separación de la funcionalidad genérica como "promedio" en una función separada, bien nombrada
  • juxt es una función bastante útil en general para extraer una lista específica de valores de componentes de un mapa
+0

Gracias, estoy aprendiendo tantas funciones útiles, ¡voy a agregar juxt a esa lista! – Adam

+0

¡Sin preocupaciones! PD. el uso de juxt en este caso es un poco inteligente, ya que está explotando el hecho de que puede usar palabras clave (": test1", etc.) como funciones. Pero puedes usarlo con cualquier función arbitraria. – mikera

+0

La [paradoja del inventor] (https://en.wikipedia.org/wiki/Inventor%27s_paradox): a veces resolver un problema general puede ser más fácil que resolver un problema específico. – Zaz

Cuestiones relacionadas