Elixir では連想配列を表現する手段として keyword list と mapの2つがある。
Keyword list
- 特定の条件のtupleのリストはkeyword list として扱われる
- listの拡張みたいな存在なので、listの特徴をそのまま受け継いでいる。ゆえにlistが長くなればなるほどサイズを取得したり、後ろのアイテムを取得したりする場合は、処理が遅くなる。
iex> list = [{:a, 1}, {:b, 2}] [a: 1, b: 2] # アクセスするときはキー名を指定できる。 iex> list[:a] 1 # 直接書いても通る iex> list = [a: 1, b: 2] # 一つ目の要素がatomでない場合はtupleのlistとして扱われる iex> list = [{"a", 1}, {"b", 2}] [{"a", 1}, {"b", 2}] # 要素数が異なる場合はtupleのlistとして扱われる iex>list = [{:a, 1}, {:b, 2, 4}] [{:a, 1}, {:b, 2, 4}] # キーの重複は許容される iex> list = [{:a, 1}, {:a, 2}] [a: 1, a: 2] # アクセスするとListの先頭から先に見つかった要素が表示される。 iex> list[:a] 1
- 通常のListと同じ操作が使える
iex> list = [{:a, 1}, {:b, 2}] [a: 1, b: 2] iex> list ++ [c: 3] [a: 1, b: 2, c: 3] iex> [a: 0] ++ list [a: 0, a: 1, b: 2]
Maps
- key -value のデータを扱いたいときはMapを使う。
- %{ } で囲む
- 関数の引数でMapを使ったパターンマッチを使うと便利
- 割と最近導入された仕組みで小さいMapを扱うのに適している。容量の大きなKeyが必要になるデータはHashDict を使ったほうが性能が良い。
iex> map = %{:a => 1, :b => 2} %{a: 1, b: 2} # キー名を指定してアクセスできる iex> map[:a] 1 # 存在しないキーはnilが返る iex> map[:c] nil # キーのデータ型が統一されていなくても通る iex> map = %{:a => 1, 2 => :b} %{2 => :b, :a => 1} # キーの重複は許可されず、後勝ち iex> map = %{:a => 1, :a => 2} %{a: 2} # valiableをキーに指定することはできない iex> key = :a :a iex> map = %{key => 1} ** (CompileError) iex:61: illegal use of variable key in map key (elixir) src/elixir_translator.erl:344: :elixir_translator.translate_arg/3 (elixir) src/elixir_map.erl:154: anonymous fn/7 in :elixir_map.translate_map/4 (stdlib) lists.erl:1352: :lists.mapfoldl/3 (elixir) src/elixir_map.erl:153: :elixir_map.translate_map/4 (elixir) src/elixir_translator.erl:17: :elixir_translator.translate/2 # mapにvaliableでアクセスすることはできる iex> map[key] 1 # mapを更新する iex> %{map | :a => 2} %{2 => :b, :a => 2} # 更新するときに存在しないキーを指定すると例外 iex> %{map | :c => 3} ** (ArgumentError) argument error (stdlib) :maps.update(:c, 3, %{a: 1, b: 2}) (stdlib) erl_eval.erl:255: anonymous fn/2 in :erl_eval.expr/5 (stdlib) lists.erl:1261: :lists.foldl/3
- パターンマッチ
iex> map = %{:a => 1, :b => 2, :c => 3} # 必ずマッチする iex> %{} = map %{a: 1, b: 2, c: 3} # 部分的にマッチする iex> %{:b => 2} = map %{a: 1, b: 2, c: 3} # 値を束縛する iex> %{:a => a, :b => 2, :c => c} = map %{a: 1, b: 2, c: 3} iex> a 1 iex> c 3 # マッチしないと例外 iex> %{:a => 2} = map ** (MatchError) no match of right hand side value: %{a: 1, b: 2, c: 3}
Dicts
- Keyword list と Map は dictionaryが実装されている(behaviourと呼ばれてるらしい)ので Dict moduleのメソッドが使える