Slide 1

Slide 1 text

@ 2021 Loglass Inc. 1 木構造のデータって意外と多くない? Kotlinと探索アルゴリズムでスマートに 木構造データをさばく 2021/9/22 株式会社ログラス 佐藤有斗

Slide 2

Slide 2 text

@ 2021 Loglass Inc. 2 ● 佐藤 有斗(ゆいと) ● 株式会社ログラス ● TypeScriptとKotlinとScalaの民 ● 好きなゲーム: スマブラ、原神 # 自己紹介

Slide 3

Slide 3 text

@ 2021 Loglass Inc. 3 # 株式会社ログラスについて ● 創業2年目のシードスタートアップ ● プランニング・クラウド ● Kotlin × Spring Boot 次世代型プランニング・クラウド「Loglass」を開発するログラス、 ICCサミット 「カタパルト・グランプリ」で優勝 https://prtimes.jp/main/html/rd/p/000000036.000052025.html

Slide 4

Slide 4 text

@ 2021 Loglass Inc. 4 木構造のデータってよく使いますか?

Slide 5

Slide 5 text

@ 2021 Loglass Inc. 5 # 木構造のデータってこんなの(以下ツリーと呼びます) 1 11 13 12 111 112 1121

Slide 6

Slide 6 text

@ 2021 Loglass Inc. 6 # 世の中にツリーはとても多い ディレクトリ 部署 家系図 法人 タスク

Slide 7

Slide 7 text

@ 2021 Loglass Inc. 7 # Loglassにもたくさん出てくるツリー

Slide 8

Slide 8 text

@ 2021 Loglass Inc. 8 # よくあるケース: ツリーを他のツリーに変換したい 1 11 13 12 111 112 1121 10 110 130 120 1110 1120 11210 10倍!

Slide 9

Slide 9 text

@ 2021 Loglass Inc. 9 再帰関数を書くか、、、

Slide 10

Slide 10 text

@ 2021 Loglass Inc. 10 再帰関数を書くか、、、

Slide 11

Slide 11 text

@ 2021 Loglass Inc. 11 再帰関数を書くか、、、

Slide 12

Slide 12 text

@ 2021 Loglass Inc. 12 読みづらい😇

Slide 13

Slide 13 text

@ 2021 Loglass Inc. 13 # 普段使いにはつらい再帰関数 ● そもそも処理が追いづらい ○ 土日の趣味プログラミング以外で出会いたくない

Slide 14

Slide 14 text

@ 2021 Loglass Inc. 14 mapみたいな関数があればな〜〜〜〜〜〜〜

Slide 15

Slide 15 text

@ 2021 Loglass Inc. 15 例えば: listOf(1,2,3).map { it * 10 }

Slide 16

Slide 16 text

@ 2021 Loglass Inc. 16 tree.map { it * 10 } な感じで書きたいな〜

Slide 17

Slide 17 text

@ 2021 Loglass Inc. 17 よし、作ろう

Slide 18

Slide 18 text

@ 2021 Loglass Inc. 18 1. 木構造を抽象化する 2. mapのインターフェースを考える 3. mapの実装をする # Tree.mapを作るまでのステップ

Slide 19

Slide 19 text

@ 2021 Loglass Inc. 19 1. 木構造を抽象化する 2. mapのインターフェースを考える 3. mapの実装をする # Tree.mapを作るまでのステップ

Slide 20

Slide 20 text

@ 2021 Loglass Inc. 20 # 1. 木構造を抽象化する ● ジェネリクスを使って木構造の中のデータは何でもとれるようにする

Slide 21

Slide 21 text

@ 2021 Loglass Inc. 21 # 1. 木構造を抽象化する ● これでどんなデータでも木構造にできる! あ い え う Tree True False False Tree Hoge1 Hoge2 Hoge3 Tree

Slide 22

Slide 22 text

@ 2021 Loglass Inc. 22 1. 木構造を抽象化する 2. mapのインターフェースを考える 3. mapの実装をする # Tree.mapを作るまでのステップ

Slide 23

Slide 23 text

@ 2021 Loglass Inc. 23 # 2. mapのインターフェースを考える tree.map { it * 10 } な感じで書きたいな〜

Slide 24

Slide 24 text

@ 2021 Loglass Inc. 24 # 2. mapのインターフェースを考える tree.map { data -> data * 10 } ちょっと整形

Slide 25

Slide 25 text

@ 2021 Loglass Inc. 25 # 2. mapのインターフェースを考える tree.map { data -> data * 10 } ここは (Int) -> Int

Slide 26

Slide 26 text

@ 2021 Loglass Inc. 26 # 2. mapのインターフェースを考える tree.map { data -> data * 10 } つまり (Treeの中身) -> 変換したい型の関数

Slide 27

Slide 27 text

@ 2021 Loglass Inc. 27 # 2. mapのインターフェースを考える tree.map { data -> data * 10 } つまり (T) -> S の関数

Slide 28

Slide 28 text

@ 2021 Loglass Inc. 28 # 2. mapのインターフェースを考える 1 2 4 3 Tree あ い え う Tree f: (T) => S ● つまりこう

Slide 29

Slide 29 text

@ 2021 Loglass Inc. 29 1. 木構造を抽象化する 2. mapのインターフェースを考える 3. mapの実装をする # Tree.mapを作るまでのステップ

Slide 30

Slide 30 text

@ 2021 Loglass Inc. 30 # 3. mapの実装をする

Slide 31

Slide 31 text

@ 2021 Loglass Inc. 31 # 3. mapの実装をする 自分自身に関数を適用 さっきの 「1 -> “あ”」の関数

Slide 32

Slide 32 text

@ 2021 Loglass Inc. 32 # 3. mapの実装をする 子供全員に再帰関数を 適用する

Slide 33

Slide 33 text

@ 2021 Loglass Inc. 33 できた!

Slide 34

Slide 34 text

@ 2021 Loglass Inc. 34 全体像

Slide 35

Slide 35 text

@ 2021 Loglass Inc. 35 FIN

Slide 36

Slide 36 text

@ 2021 Loglass Inc. 36 ではない

Slide 37

Slide 37 text

@ 2021 Loglass Inc. 37

Slide 38

Slide 38 text

@ 2021 Loglass Inc. 38 10000階層のツリー

Slide 39

Slide 39 text

@ 2021 Loglass Inc. 39

Slide 40

Slide 40 text

@ 2021 Loglass Inc. 40 スタックオーバーフロー!!!

Slide 41

Slide 41 text

@ 2021 Loglass Inc. 41 # ⚠ここからは尺の関係上ざっくり説明します ● 全てを理解しようとしないでください ● あ〜こんなやり方あるんだな〜で大丈夫です 👍 ● コードはこちらです ○ https://github.com/YuitoSato/kotlin-sandbox/blob/master/src/main/kotlin/tree/Tre e.kt

Slide 42

Slide 42 text

@ 2021 Loglass Inc. 42 # 再帰関数におけるスタックオーバーフローとは ● 子の計算を全て終えないと親の関数が終わらない ○ 計算時の関数内ローカル変数をスタックに保持するが、そこがパンクする

Slide 43

Slide 43 text

@ 2021 Loglass Inc. 43 # では世の中の全ての再帰関数はスタックオーバーフローを起こすの? ● 言語によってはNo ● 一部の言語には末尾再帰最適化というものが実装されている

Slide 44

Slide 44 text

@ 2021 Loglass Inc. 44 # 末尾再帰最適化 (tail call optimization) とは~ ざっくり説明 ● 一部のプログラムではビルド時に 末尾呼び出しの再帰関数を単なる While文に最適化してい る

Slide 45

Slide 45 text

@ 2021 Loglass Inc. 45 # これは末尾再帰

Slide 46

Slide 46 text

@ 2021 Loglass Inc. 46 # これは末尾再帰ではない 最後に評価される関数は Treeのコンストラクタ

Slide 47

Slide 47 text

@ 2021 Loglass Inc. 47 別のやり方でやろう

Slide 48

Slide 48 text

@ 2021 Loglass Inc. 48 最適化が使えないので自力Whileをする

Slide 49

Slide 49 text

@ 2021 Loglass Inc. 49 # map処理のおさらい 1 2 4 3 5 6

Slide 50

Slide 50 text

@ 2021 Loglass Inc. 50 # map処理のおさらい あ 2 4 3 5 6

Slide 51

Slide 51 text

@ 2021 Loglass Inc. 51 # map処理のおさらい あ い 4 3 5 6

Slide 52

Slide 52 text

@ 2021 Loglass Inc. 52 # map処理のおさらい あ い 4 う 5 6

Slide 53

Slide 53 text

@ 2021 Loglass Inc. 53 # map処理のおさらい あ い え う 5 6

Slide 54

Slide 54 text

@ 2021 Loglass Inc. 54 # map処理のおさらい あ い え う お 6

Slide 55

Slide 55 text

@ 2021 Loglass Inc. 55 幅優先探索だ!💡

Slide 56

Slide 56 text

@ 2021 Loglass Inc. 56 # 幅優先探索にはキュー(先に入れたものが先に出る)を使う 1 2 4 3 5 6 処理待ちノードを入れるキュー 優先処理 1

Slide 57

Slide 57 text

@ 2021 Loglass Inc. 57 # 幅優先探索にはキュー(先に入れたものが先に出る)を使う あ 2 4 3 5 6 処理待ちノードを入れるキュー 優先処理 2 3 4 1

Slide 58

Slide 58 text

@ 2021 Loglass Inc. 58 # 幅優先探索にはキュー(先に入れたものが先に出る)を使う あ い 4 3 5 6 処理待ちノードを入れるキュー 優先処理 3 4 5 6 2

Slide 59

Slide 59 text

@ 2021 Loglass Inc. 59 # こう実装してみます

Slide 60

Slide 60 text

@ 2021 Loglass Inc. 60 # こう実装してみます キューと最終的に返す ツリーの初期化。

Slide 61

Slide 61 text

@ 2021 Loglass Inc. 61 # こう実装してみます キューから取り出して 関数を適用

Slide 62

Slide 62 text

@ 2021 Loglass Inc. 62 # こう実装してみます 処理したノードを 最終的なツリーに足す

Slide 63

Slide 63 text

@ 2021 Loglass Inc. 63 # こう実装してみます 次に処理されるノード(子 供)をキューにいれる

Slide 64

Slide 64 text

@ 2021 Loglass Inc. 64 # こう実装してみます 最後にリターン

Slide 65

Slide 65 text

@ 2021 Loglass Inc. 65 # イメージ: ① キューと空のツリーを用意する 1 2 4 3 5 6

Slide 66

Slide 66 text

@ 2021 Loglass Inc. 66 # イメージ: ② キューに積む 1 2 4 3 5 6 1

Slide 67

Slide 67 text

@ 2021 Loglass Inc. 67 # イメージ: ③ キューの先頭に関数を適用する 1 2 4 3 5 6 あ

Slide 68

Slide 68 text

@ 2021 Loglass Inc. 68 # イメージ: ④ キューの先頭を最終的なツリーに追加する 1 2 4 3 5 6 あ

Slide 69

Slide 69 text

@ 2021 Loglass Inc. 69 # イメージ: ④ 子供を全てキューに積む 1 2 4 3 5 6 あ 2 3 4

Slide 70

Slide 70 text

@ 2021 Loglass Inc. 70 # イメージ: ①~④を繰り返す 1 2 4 3 5 6 あ い え う お か

Slide 71

Slide 71 text

@ 2021 Loglass Inc. 71 できた!(強引)

Slide 72

Slide 72 text

@ 2021 Loglass Inc. 72 今回のコードはこちらに全てあります。 https://github.com/YuitoSato/kotlin-sandbox/blo b/master/src/main/kotlin/tree/Tree.kt

Slide 73

Slide 73 text

@ 2021 Loglass Inc. 73 # まとめ → 世の中にツリーは多い → ツリーのデータ変換は再帰関数が多くてつらい → map関数を作って再帰処理を隠蔽する → と思ったらスタックオーバーフローしてしまった → スタックオーバーフローを回避するために幅優先探索で実装する → ハッピー!

Slide 74

Slide 74 text

@ 2021 Loglass Inc. 74 ハッピー!(強引)

Slide 75

Slide 75 text

@ 2021 Loglass Inc. 75 # 余談: Q. スタックオーバーフローってどれくらいで起きるの? 🤔 A. 手元のマシンで試したら10000階層くらいで発生した(※JVM内で格納しているスタックの量 に寄ります)

Slide 76

Slide 76 text

@ 2021 Loglass Inc. 76 # 余談: Q. Loglassってそんな階層の深いツリーを扱うの? 🤔 A. 扱いません

Slide 77

Slide 77 text

@ 2021 Loglass Inc. 77 # 余談: Q. え、じゃあ幅優先探索の実装とか、必要、、? A. 要りません

Slide 78

Slide 78 text

@ 2021 Loglass Inc. 78 結論: ほぼほぼ再帰処理実装でOK(オチです)

Slide 79

Slide 79 text

@ 2021 Loglass Inc. 79 ありがとうございました! Kotlinで複雑なデータ構造に 立ち向かいたい人Welcomeです!