2012-02-01 8 views
14

¿Cómo agrupar una colección de mapas por varias claves?agrupar por varias teclas en Clojure

Por ejemplo:

(def m1 [{:a 1 :b 2 :c 3} 
     {:a 1 :b 2 :c 4} 
     {:a 1 :b 4 :c 3} 
     {:a 1 :b 4 :c 3}]) 

(group-by-x [:a :b] m1) 

me gustaría volver a este:

[{:a 1 :b 2} [{:a 1 :b 2 :c 3}{:a 1 :b 2 :c 4}], 
{:a 1 :b 4} [{:a 1 :b 4 :c 3}{:a 1 :b 4 :c 3}]] 

Respuesta

18
(group-by #(select-keys % [:a :b]) m1) 

Esto devuelve un mapa:

{{:b 2, :a 1} [{:a 1, :c 3, :b 2} {:a 1, :c 4, :b 2}], 
{:b 4, :a 1} [{:a 1, :c 3, :b 4} {:a 1, :c 3, :b 4}]} 

para obtener exactamente el valor de retorno lo especificó, envuélvalo en (vec (apply concat ...)):

(vec (apply concat (group-by #(select-keys % [:a :b]) m1))) 
; => as in the question text 

Esto es equivalente, pero quizás más bonita:

(->> (group-by #(select-keys % [:a :b]) m1) 
    (apply concat) 
    vec) 
+9

También puede '(grupo-por (Juxt: a: b) coll)', que le da pares en lugar de los mapas como las llaves. A menudo, este será un formato más útil que tener docenas de mapas con las teclas ': a' y': b', pero eso depende completamente de su aplicación. – amalloy

+0

@amalloy: Derecha. Eso fue lo que escribí antes de darme cuenta de que las especificaciones requieren un mapa. Estoy de acuerdo en que los vectores posiblemente sean más útiles, debería haberlo incluido en la respuesta ... Gracias por corregir esta evidente omisión. :-) –