動かざることバグの如し

近づきたいよ 君の理想に

Elixir マップの値を更新する方法3選

環境

  • Elixir 1.x

やりたいこと

例えば、以下のようなMapがあったとする。

user = %{name: "Taro", gender: "man", city: "Tokyo"}

ここのcityのTokyoの値を変更したり、あたらしくidのキーを追加したい。

存在するキーを更新する場合

パイプ文字を使った new_map = %{ old_map | key => value, ...} を使う。

new_user = %{user| city: "sendai"}
# => %{city: "sendai", gender: "man", name: "Taro"}

引数に続けば複数一括更新できる。

new_user = %{user | city: "sendai", name: "Ziro"}

キーが存在しなかった場合エラーになる。

iex(10)> new_user = %{user| id: 123}                         
** (KeyError) key :id not found in: %{city: "Tokyo", gender: "man", name: "Taro"}
    (stdlib) :maps.update(:id, 123, %{city: "Tokyo", gender: "man", name: "Taro"})
    (stdlib) erl_eval.erl:255: anonymous fn/2 in :erl_eval.expr/5
    (stdlib) lists.erl:1263: :lists.foldl/3

キーが存在しない場合

Map.put_new/3 を使う必要がある。

new_user = Map.put user, :id, 123
# => %{city: "Tokyo", gender: "man", id: 123, name: "Taro"}

こっちはキーが存在していても更新される。

new_user = Map.put user, :city, "sendai"
# => %{city: "sendai", gender: "man", name: "Taro"}

このように書くこともできる。

user |> Map.put(:city, "sendai")

Map.merge/2 も利用可能

Map.merge(user, %{city: "sendai"} )

じゃあキーの有無考えなくていい Map.put 全部使えばいいじゃんって話だが、本来存在しなきゃいけないときに気づけない場合もある。

ちゃんと使いどきを考えよう