10
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ElixirAdvent Calendar 2024

Day 6

Elixirのチートシートを作ろう #3

Last updated at Posted at 2024-12-05

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]

...これだけ?これだけで一日?うわぁ、先を考えるとお辛いな。
アドベンドカレンダーどころか、アドベンド四半期にならない?

10
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?