Clojureでデータを指定のキーごとにまとめる

user> (def data 
        [{:type "key1" :value "key1-value"} 
         {:type "key1" :value "key1-value2"} 
         {:type "key2" :value "key2-value"} 
         {:type "key3" :value "key3-value"}])

こんなデータを、:typeの値ごとにまとめたい(SQLでいうところのGROUP BYみたいなことをしたい) という場面があったので調べてみたら、そのものズバリgroup-byという関数があったのでメモしておく

group-by - clojure.core | ClojureDocs - Community-Powered Clojure Documentation and Examples

user> (group-by :type data)
{"key1" [{:type "key1", :value "key1-value"} {:type "key1", :value "key1-value2"}], "key2" [{:type "key2", :value "key2-value"}], "key3" [{:type "key3", :value "key3-value"}]}

第一引数に分類するキーを指定し、第二引数にデータ自体を指定すると 内容を一つづつ見ていき、第一引数で指定したキーの値ごとにベクターを作るという動きになっている模様。

これだけでも十分使えるんだけど、どうせならキーの値の部分をキーワードにしたかったので更に調べたら 第位置引数には関数も指定できて、その関数を通した結果が分類のキーになるというのを知ったので こんな感じにしてみたらうまいこと動いた。

user> (group-by (fn [x] (keyword (:type x))) data)
{:key1 [{:type "key1", :value "key1-value"} {:type "key1", :value "key1-value2"}], :key2 [{:type "key2", :value "key2-value"}], :key3 [{:type "key3", :value "key3-value"}]}

更に後から同僚の人にAnonymouse Function Literalなんてのを教えてもらって更に短くできることを知った。 http://clojure.org/reference/reader#_dispatch

user> (group-by #(keyword (:type %)) data)
{:key1 [{:type "key1", :value "key1-value"} {:type "key1", :value "key1-value2"}], :key2 [{:type "key2", :value "key2-value"}], :key3 [{:type "key3", :value "key3-value"}]}