1. Over View
いや、LISTだけでどんどん行数増えてたんで、しかたなく。
2. 解説
2.1 タプル
さて、Elixir Schoolの引用から。
https://elixirschool.com/ja/lessons/basics/collections#%E3%82%BF%E3%83%97%E3%83%AB-4
タプルはリストに似ていますが、各要素はメモリ上に隣接して格納されます。 このため、タプルの長さを得るのは高速ですが、修正を行うのは高コストとなります。というのも、新しいタプルは全ての要素がメモリにコピーされるからです。タプルは波括弧を用いて定義されます:
iex(69)> {3.14, :pie, "Apple"}
{3.14, :pie, "Apple"}
なんだ、listの[]が{}で囲まれる様になっただけじゃん…なんて安易な違いじゃない様です。
一文でさらっと解説されてますが、
- 各要素はメモリ上に隣接して格納されます。
- タプルの長さを得るのは高速ですが、修正を行うのは高コストとなります。
というのも、新しいタプルは全ての要素がメモリにコピーされるからです。
先ほどは気楽にLISTに追加をしてましたが、それが全部「毎回メモリ上に変数をコピーする」ので、
追加とかは困りますね。
これ、LISTの格納のされ方との違いでもあるのですが、複雑な話になるので、別のコラムにします。
さて、使い道。
タプルの長さを得るのは高速なので、関数の引数なんかに使われるそうです。
Elixir Schoolのサンプルが、今後のいろんな勉強の予告編みたいになっちゃいますが、
iex(1)> File.read(".condarc")
{:ok, "channels:\r\n - defaults\r\n"}
iex(2)> File.read(".condarsss")
{:error, :enoent}
関数が、:ok, :errorと言うアトムを返しています。
こういう、もう変わらない要素をコレクションするときに使うわけです。
では、これがどう便利に使われるかは…パターンマッチでやりましょう。
2.2 キーワードリスト
さぁ、みなさんご一緒に。
(ぴかぴかぴかー)キーワードリスト
連想コレクションですな。そう、僕が大好き連想配列。
さて、Elixir Schoolの引用
キーワードリストとマップはElixirの連想コレクションです。
Elixirでは、キーワードリストは最初の要素がアトムのタプルからなる特別なリストで、リストと同様の性能になります。
あー、ここでタプル登場。
タプルは要素数が決まってるから、こう言うと時に便利なのね。
これも、関数への引数指定なんかに使われてますな。
iex(44)> [foo: "bar", hello: "world"]
[foo: "bar", hello: "world"]
iex(45)> [foo: "bar", hello: "world"]
[foo: "bar", hello: "world"]
iex(46)> [{:foo, "bar"}, {:hello, "world"}]
[foo: "bar", hello: "world"]
iex(47)> [foo: "bar", hello: "world"]
[foo: "bar", hello: "world"]
…さて、こんな感じでキーワードリストにアクセスできるのですわ。
atomが、コロンを後ろにつけるfoo:から、取り出すときは:fooと前に着けているのに注意
iex(3)> [foo: "bar", hello: "world"][:foo]
"bar"
iex(52)> mokemoke=[foo: "bar", hello: "world"]
[foo: "bar", hello: "world"]
iex(53)> mokemoke[:foo]
"bar"
キーワードさえあれば、キーワードリストから要素を簡単に取り出せるので、便利ですね。
2.3 マップ
さて、Elixir Schoolの引用
Elixirではマップは”花形の”キーバリューストアです。
キーワードリストとは違ってどんな型のキーも使え、順序付けされません。
マップは %{} 構文で定義することができます:
…なんか、こいつ、頭にのってやがりますぜ、花形だってさ。で、その便利さを見てみましょう。
いや、チートシートなんで、お手柔らかに…
iex(58)> map = %{:foo => "bar", "hello" => :world}
%{:foo => "bar", "hello" => :world}
iex(59)> map[:foo]
"bar"
iex(60)> map["hello"]
:world
最初のkeywordの部分がどんな方でも受け付けるので、とても便利。
さらにっ、変数をマップのキーに出来てますなぁ。
iex(65)> key = "hello"
"hello"
iex(66)> %{"hello" => "world"}
%{"hello" => "world"}
iex(67)> %{key => "world"}
%{"hello" => "world"}
※実行順を変更しております
ここからが、花形たるゆえんか!?(師範リスペクト)
さて、Elixir Schoolの引用
アトムのキーだけを含んだマップには特別な構文があります:
上記の出力からわかるように、アトムのキーだけを含んだマップには特別な構文があります:
%{:foo => "bar", "hello" => :world}
これを
iex(73)> %{foo: "bar", world: "hello"}
%{foo: "bar", world: "hello"}
iex(74)>
と、書けるんですね。便利。
さらに花形な表現が…
重複したキーが追加された場合は、前の値が置き換えられます:
ちゃんと、警告も出ますなー=。
iex(71)> %{:foo => "bar", :foo => "hello world"}
warning: key :foo will be overridden in map
iex:71
%{foo: "hello world"}
iex(72)>
これは、地味に便利ですね。
いろんな機能はさらに続きます。
iex(78)> map = %{foo: "bar", hello: "world"}
%{foo: "bar", hello: "world"}
iex(79)> map.hello
"world"
iex(80)> map.foo
"bar"
そして、最後のびっくり
マップのもう一つの興味深い特性は、マップの更新のための固有の構文があることです(注: 更新と言っていますが、新しいmapが作成されます):
では、見てみましょう。
iex(86)> map = %{foo: "bar", hello: "world"}
%{foo: "bar", hello: "world"}
iex(87)> %{map | foo: "baz"}
%{foo: "baz", hello: "world"}
Elixir Schoolにも書いてありますが、新しいキーを作成するには、以下の様にput/2を使用します。
Map.put(map, :foo, "baz")
%{foo: "baz", hello: "world"}
listとは違い、ミニデータベースみたいな感じですね。
3. 本日のチートシート
3.1 タプル
説明 | 例 |
---|---|
タプルは、{}で括られ、各要素を, 区切ります。 | {1, "OverView"} |
タプルの長さを得るのは高速ですが、修正を行うのは高コストとなります。 というのも、新しいタプルは全ての要素がメモリにコピーされるからです。 |
3.2 キーワードリスト
説明 | 例 |
---|---|
キーワードリストは、最初の要素がアトムのタプルになります。 | [foo: "bar", hello: "world"] |
表記が4つあるのに注意してください。 [foo: "bar", hello: "world"] [foo: "bar", hello: "world"] [{:foo, "bar"}, {:hello, "world"}] [foo: "bar", hello: "world"] |
すべてが上と同じ [foo: "bar", hello: "world"] |
atomを指定して、キーワードリストにアクセス | |
iex(52)> mokemoke=[foo: "bar", hello: "world"] [foo: "bar", hello: "world"] iex(53)> mokemoke[:foo] "bar" |
3.3 マップ
さて、Elixir Schoolの引用
説明 | 例 |
---|---|
マップは %{} 構文で定義します。 マップはキーワードリストと違い、どんな方もキーに出来ます |
iex(58)> map = %{:foo => "bar", "hello" => :world} %{:foo => "bar", "hello" => :world} |
マップには、キーでアクセスできます | iex(58)> map = %{:foo => "bar", "hello" => :world} %{:foo => "bar", "hello" => :world} iex(59)> map[:foo] "bar" iex(60)> map["hello"] :world |
変数をマップのキーに出来ます | iex(65)> key = "hello" "hello" iex(66)> %{"hello" => "world"} %{"hello" => "world"} |
アトムのキーだけを含んだマップには特別な構文で書けます | %{:foo => "bar", "hello" => :world} これを iex(73)> %{foo: "bar", world: "hello"} %{foo: "bar", world: "hello"} iex(74)> と、書ける |
重複したキーが追加された場合は、前の値が置き換えられます | iex(71)> %{:foo => "bar", :foo => "hello world"} warning: key :foo will be overridden in map iex:71 %{foo: "hello world"} iex(72)> |
アトムのキーだけを含んだマップには特別な構文で要素にアクセスできます | iex(78)> map = %{foo: "bar", hello: "world"} %{foo: "bar", hello: "world"} iex(79)> map.hello "world" iex(80)> map.foo "bar" |
マップの更新のための固有の構文がある | iex(86)> map = %{foo: "bar", hello: "world"} %{foo: "bar", hello: "world"} iex(87)> %{map |
新しいキーを作成するには、put/2を使用します | Map.put(map, :foo, "baz") %{foo: "baz", hello: "world"} |