clojureでmapを扱う基本的な関数

clojureを何も知らないままとりあえず1つプログラム書いてみて、色々知らないまま書いていたのでとても苦労しました

便利な関数がいっぱいあったのでメモ。

ネストしたmapの操作

jsonを扱っていると時にネストの深いhash-mapをいじらないといけない時がありますね

get-in

こんなxがあったとき、おどろくべきことに一々(:key1 (:key2 ...と書いていました。恐ろしい

user=> (def x {:foo {:bar {:baz 1} :hoge 2}})
#'user/x
user=> (:baz (:bar (:foo x)))
1

get-inという関数がちゃんと用意されていました。

user=> (get-in x [:foo :bar :baz])
1

assoc-in

key valueを追加したい、もしくは単に値を変えたい場合はassoc-in

assoc-inを知るまではこんなふうに書いていましたが、

user=> (assoc x :foo (assoc (:foo x) :hoge 10))
{:foo {:hoge 10, :bar {:baz 1}}}

これで十分です。

user=> (assoc-in x [:foo :bar :piyo] 10)
{:foo {:hoge 2, :bar {:piyo 10, :baz 1}}}

update-in

関数を適用して更新したいときはupdate-in

user=> (defn f [x] (+ x 10))
#'user/f
user=> (update-in x [:foo :hoge] f)
{:foo {:hoge 12, :bar {:baz 1}}}

ちょっと違うかもだけどけど->

第1引数(?)にその後に続く関数(?)を適用していける感じのマクロ。 これを使えばこんな風になります

user=> (-> x :foo :bar :baz)
1

jsonを使うときのメモ

clojureでjsonといえば、https://github.com/clojure/data.jsonを使いますよね(多分)

これ、普通に使うと文字列からjsonにデコードする時にキーがstringになってしまうんですね。

これは不便。

(get (get (get x "foo") "bar") "baz")

みたいになってしまう。(はず)

しかし、githubのREADMEの例にも書いてあるように、

(json/read-str "{\"a\":1,\"b\":2}"
               :key-fn keyword)

このように:key-fn keywordを指定すればキーがKeywordになってくれます!

便利