1. OverView
さて、いきなりですが、コレクションです。
コレクションコレクション、やっほーやっほー…それはさておき。
データをまとめて扱う、データ構造の事です。
お説教臭くなりますが、お許しください。
数字とか文字列の羅列、たくさんありますよね?
Section | Title |
---|---|
1 | OverView |
2 | まずは解説 |
3 | 本日のチートシート |
これ、僕の記事の章立てです。
でも、この組み合わせ、どう管理しましょうか?
[1,"OverView",2,"まずは解説",3,"本日のチートシート"]
を、なんかそれっぽいですね。
今、あなたは、無意識に「section, titleの順でデータが並んでいる」と言う「解釈」をしてくれたのです。
ええ、忖度でもいいですよ。
ところが、赤の他人にいきなり、上のLISTを見せると、
「[]で括られてるから、一行かな?おそらく番号だね。二つ目の文字列は…おそらくタイトル?」
と言う感じで、元のテーブルを想像してくれる保証はないです。
では、どう他人やプログラムに解釈を伝えようか?と言うお話です。
なので、複数のコレクションが出てくるので、ゆっくりお愉しみください。
…いや、俺、さっぱりわかんねーので、数ヶ月LISPの本読んで…LISPのコンパイラ作る本でやっと理解したw
2. まずは解説
2.1 LISTその1
まずはlist、根源ですね、のぞき込むとあっちからのぞき込んでる奴。
LISTは、[]で括られ、各要素を, 区切ります。
そう、これ
[1,"OverView",2,"まずは解説",3,"本日のチートシート"]
Elixir Schoolによれば
リストは値の単純なコレクションで、複数の型を含むことができます。また、一意ではない値を含むことができます:
だそうです。
「一意ではない値を含むことが出来ます」
ここに注目して下さい…いや、注目しなくても、僕が粘着します。すっごく。
まずは例題をやりながら、進めましょう。
iex(30)> [3.14, :pie, "Apple", 3.14]
[3.14, :pie, "Apple", 3.14]
ちょっと、例を変えております、3.14が繰り返されてる。
この順番自体は不変ですので、1番目と4番目が区別がつかなくなることはないです。
以下、後ろに追加してみました。
iex(30)> [3.14, :pie, "Apple", 3.14, :cake, "berry"]
他の本の受け売りなのですが、リストの並びは人間(またはプログラム、プログラマ)が解釈するので
あって、リストはリストでしかないそうで。
このリストの連結も出来ます。
iex(24)> [3.14, :pie, "Apple"] ++ [3.14, :cake, "berry"]
[3.14, :pie, "Apple", 3.14, :cake, "berry"]
さて、今度はリストの減算。
マッチしたものが、削除されます。
iex(25)> [3.14, :pie, "Apple"] -- [3.14, :cake, "berry"]
[:pie, "Apple"]
iex(26)> [3.14, 3.14, :pie, "Apple"] -- [3.14, :cake, "berry"]
[3.14, :pie, "Apple"]
二つの目の例、3.14が繰り返されてますが、減算では、最初にマッチしたものだけが削除されてる
ことに注意してください。
2.2 LISTその2
先ほどの「一位ではない値を含む」にこだわってみましょう。
では、LISTの一部を取り出すのに、どうしようか?と言う話となります。
まずは、簡単な方からやります。
解説の都合上、両方取り上げますが、2.2.2は「ああ、こいつの自己満足だな」くらいに読み飛ばしてください。
基本なんで絶対に書きたかったんですが「なんでこれ使うの?」と言うのが後からわかる仕組みなので、今、
すぐに理解しろと言うブツではないのです。
2.2.1 インデックスを使った、要素の取り出し
まずは、このLIST、
[3.14, 3.99, :pie, "Apple"]
一つ一つの要素には、番号が振られているので、そいつを利用して、取り出せます。
iex(46)> Enum.at([3.14, 3.99, :pie, "Apple"],0)
3.14
iex(47)> Enum.at([3.14, 3.99, :pie, "Apple"],1)
3.99
iex(48)> Enum.at([3.14, 3.99, :pie, "Apple"],2)
:pie
要素は、0から始まるので、気を付けてくださいね。
ゼロオリジンと言います。
2.2.2 hd/tl(頭部/尾部)
リストを扱う際には、リストの頭部と尾部を利用したりします。頭部はそのリストの最初の要素で、尾部は残りの要素になります。
Elixirはこれらを扱うために、 hd と tl という2つの便利な関数を用意しています。
※これ、のちほど、再帰呼び出しと言うもので、「先頭だけ処理して、後ろの方は自分自身を呼び出して処理する」とかやるので。。。
うん、その時にやろう。
今はhd/1とtl/2を使ってみましょう。
iex(34)> hd [3.14, :pie, "Apple"]
3.14
iex(35)> tl [3.14, :pie, "Apple"]
[:pie, "Apple"]
尾部と言いますが、残りの要素全部なのに注意してください。
hdはリストの先頭が返ってくるのだけど、tlは、その残り全部が返ってくる。
どう使うんじゃ?と思った時に、さっきの記憶がよみがえるんですね。
これ、意外と面白い仕組みで、
hd([3.14, :pie, "Apple", 3.14, :cake, "berry"])
...3.14って、先頭だけみてどーすんじゃ?
と思うわけですが、
iex(40)> hd([ [3.14, :pie, "Apple"], [3.14, :cake, "berry"] ])
[3.14, :pie, "Apple"]
iex(41)> tl([ [3.14, :pie, "Apple"], [3.14, :cake, "berry"]])
[[3.14, :cake, "berry"]]
ほら、LISTは「複数の型を含むことが出来る」ので、LISTの中にLISTが入ります。
リストはリストで入れ子出来るので、「先頭のリスト」だけ取り出せますな。
こうなると、「なんでもリストにほおりこんで、hdで取り出して処理する、tlはループなどで再度処理する
と言う仕組みが見えてきますなぁ。
文頭の例を見てみましょう。
[1,"OverView",2,"まずは解説",3,"本日のチートシート"]
ちょっと弄って
[[1, "OverView"], [2, "まずは解説"], [3, "本日のチートシート"]]
SectionとTitleの組み合わせで、listを作り、それをまとめてみました。
こうすれば、
iex(34)> hd([[1,"OverView"],[2,"まずは解説"],[3,"本日のチートシート"]])
[1, "OverView"]
先頭の取り出し、では、その次も
iex(35)> hd(tl([[1,"OverView"],[2,"まずは解説"],[3,"本日のチートシート"]]))
[2, "まずは解説"]
最後の奴
iex(38)> hd(tl(tl([[1,"OverView"],[2,"まずは解説"],[3,"本日のチートシート"]])))
[3, "本日のチートシート"]
…わけわからんですね。Elixっらしく、パイプでやります。
うん。後でパイプも説明するけど、使わんと訳が分からんままなので、許してね。
iex(40)> tl([[1,"OverView"],[2,"まずは解説"],[3,"本日のチートシート"]]) |> tl() |> hd()
[3, "本日のチートシート"]
dbg関数で、動きを確認してみましょう
iex(41)> tl([[1,"OverView"],[2,"まずは解説"],[3,"本日のチートシート"]]) |> tl() |> hd() |> dbg()
[iex:41: (file)]
tl([[1, "OverView"], [2, "まずは解説"], [3, "本日のチートシート"]]) #=> [[2, "まずは解説"], [3, "本日のチートシート"]]
|> tl() #=> [[3, "本日のチートシート"]]
|> hd() #=> [3, "本日のチートシート"]
[3, "本日のチートシート"]
…と、くどくどやってますが、これ、理解すると楽になるので、まぁ、許してください。
3. 本日のチートシート
説明 | 例 |
---|---|
LISTは、[]で括られ、各要素を, 区切ります。 | [1, "OverView"] |
LISTの各要素は、それぞれ振られた番号(index)でアクセス出来ます。 Enum.at/2を使います Indexは0から始まるので、注意してください |
iex(63)> Enum.at([1, 2, 3, 4],3) 4 iex(64)> Enum.at([1, 2, 3, 4],1) 2 iex(65)> Enum.at([1, 2, 3, 4],0) 1 |
LISTの先頭はhd/1で取り出せます。 | iex(66)> hd([1,2,3]) 1 |
LISTの先頭以外の残りはtl/1で取り出せます。 | iex(67)> tl([1,2,3]) [2, 3] |
...これだけ?これだけで一日?うわぁ、先を考えるとお辛いな。
アドベンドカレンダーどころか、アドベンド四半期にならない?