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"}]}