2011-08-26 10 views
8

que tienen datos que tiene este aspectoGROUP BY y agregación de vector de mapas - Clojure

(def a [{:firmAccount "MSFT" :Val 10 :PE 3 } 
{:firmAccount "MSFT" :Val 15 :PE 4} 
{:firmAccount "GOG" :Val 15 :PE 3} 
{:firmAccount "YAH" :Val 8 :PE 1}]) 

que desea agrupar por en: firmAccount y luego suma el: Val y PE para cada cuenta de la empresa y obtener algo así como

[{:firmAccount "MSFT" :Val 25 :PE 7} 
    {:firmAccount "GOG" :Val 15 :PE 3}  
    {:FirmAccount "YAH" :Val 8 :PE 1}] 

es realmente una cosa trivial y en SQL que no se le ocurriría dos veces, pero ya que estoy aprendiendo clojure por favor tengan paciencia conmigo

Respuesta

8

Clojure.core tiene un grupo de función incorporada. La solución se vuelve un poco fea por la presencia de texto e int val en los mapas.

(for [m (group-by :firmAccount a)] 
    (assoc (apply merge-with + (map #(dissoc % :firmAccount) (val m))) :firmAccount (key m))) 
+1

Muchas gracias. Funciona bien para mí y es muy sucinto. También la respuesta me hizo saber cómo usar assoc, merge-with, apply, dissoc, group-by y map en un único ejemplo que es increíble. – Ash

1

Trate de crear una nueva matriz de mapa o un mapa de mapas con el mismo estructura. Puede escribir una función para agregar elementos a este nuevo mapa que sume esos campos si existe: account-account. Tal vez un mapa como este?

(def a {"MSFT" {:Val 25 :PE 7 } 
    "GOG" {:Val 15 :PE 3} 
    "YAH" {:Val 8 :PE 1}}) 

Con una función de complemento personalizado como:

(add-to-map [element map] 
    (if (contains? (find-name element)) 
    {map (add-fields element (find (find-name element)))} 
    {map element})) 
+0

Bueno, si se utiliza la función de complemento he esbozado aquí no es necesario cambiar la estructura. Usa estas ideas como quieras. –

+0

El cambio es necesario debido a la estructura de datos en la pregunta. La estructura que usa en su respuesta es la respuesta solicitada, no la entrada requerida. – mac

5

está completo y si aquí es una versión alternativa que utiliza el mapa:

(map (fn [[firmAccount vals]] 
    {:firmAccount firmAccount 
    :Val (reduce + (map :Val vals)) 
    :PE (reduce + (map :PE vals))}) 
    (group-by :firmAccount a)) 
+0

Interesante, uno. Muchas gracias – Ash