https://server-sider-kotlin.connpass.com/event/224077/
こちらのイベントの資料です。 Kotlinと探索アルゴリズムをつかって木構造のデータをKotlinのコレクションクラスのようにスマートに扱う実装について紹介しています。
@ 2021 Loglass Inc. 1木構造のデータって意外と多くない?Kotlinと探索アルゴリズムでスマートに木構造データをさばく2021/9/22 株式会社ログラス 佐藤有斗
View Slide
@ 2021 Loglass Inc. 2● 佐藤 有斗(ゆいと)● 株式会社ログラス● TypeScriptとKotlinとScalaの民● 好きなゲーム: スマブラ、原神# 自己紹介
@ 2021 Loglass Inc. 3# 株式会社ログラスについて● 創業2年目のシードスタートアップ● プランニング・クラウド● Kotlin × Spring Boot次世代型プランニング・クラウド「Loglass」を開発するログラス、 ICCサミット「カタパルト・グランプリ」で優勝https://prtimes.jp/main/html/rd/p/000000036.000052025.html
@ 2021 Loglass Inc. 4木構造のデータってよく使いますか?
@ 2021 Loglass Inc. 5# 木構造のデータってこんなの(以下ツリーと呼びます)111 1312111 1121121
@ 2021 Loglass Inc. 6# 世の中にツリーはとても多いディレクトリ部署家系図法人タスク
@ 2021 Loglass Inc. 7# Loglassにもたくさん出てくるツリー
@ 2021 Loglass Inc. 8# よくあるケース: ツリーを他のツリーに変換したい111 1312111 112112110110 1301201110 11201121010倍!
@ 2021 Loglass Inc. 9再帰関数を書くか、、、
@ 2021 Loglass Inc. 10再帰関数を書くか、、、
@ 2021 Loglass Inc. 11再帰関数を書くか、、、
@ 2021 Loglass Inc. 12読みづらい😇
@ 2021 Loglass Inc. 13# 普段使いにはつらい再帰関数● そもそも処理が追いづらい○ 土日の趣味プログラミング以外で出会いたくない
@ 2021 Loglass Inc. 14mapみたいな関数があればな〜〜〜〜〜〜〜
@ 2021 Loglass Inc. 15例えば: listOf(1,2,3).map { it * 10 }
@ 2021 Loglass Inc. 16tree.map { it * 10 } な感じで書きたいな〜
@ 2021 Loglass Inc. 17よし、作ろう
@ 2021 Loglass Inc. 181. 木構造を抽象化する2. mapのインターフェースを考える3. mapの実装をする# Tree.mapを作るまでのステップ
@ 2021 Loglass Inc. 191. 木構造を抽象化する2. mapのインターフェースを考える3. mapの実装をする# Tree.mapを作るまでのステップ
@ 2021 Loglass Inc. 20# 1. 木構造を抽象化する● ジェネリクスを使って木構造の中のデータは何でもとれるようにする
@ 2021 Loglass Inc. 21# 1. 木構造を抽象化する● これでどんなデータでも木構造にできる!あい えうTreeTrueFalse FalseTreeHoge1Hoge2 Hoge3Tree
@ 2021 Loglass Inc. 221. 木構造を抽象化する2. mapのインターフェースを考える3. mapの実装をする# Tree.mapを作るまでのステップ
@ 2021 Loglass Inc. 23# 2. mapのインターフェースを考えるtree.map { it * 10 } な感じで書きたいな〜
@ 2021 Loglass Inc. 24# 2. mapのインターフェースを考えるtree.map { data -> data * 10 }ちょっと整形
@ 2021 Loglass Inc. 25# 2. mapのインターフェースを考えるtree.map { data -> data * 10 }ここは (Int) -> Int
@ 2021 Loglass Inc. 26# 2. mapのインターフェースを考えるtree.map { data -> data * 10 }つまり (Treeの中身) -> 変換したい型の関数
@ 2021 Loglass Inc. 27# 2. mapのインターフェースを考えるtree.map { data -> data * 10 }つまり (T) -> S の関数
@ 2021 Loglass Inc. 28# 2. mapのインターフェースを考える12 43Treeあい えうTreef: (T) => S● つまりこう
@ 2021 Loglass Inc. 291. 木構造を抽象化する2. mapのインターフェースを考える3. mapの実装をする# Tree.mapを作るまでのステップ
@ 2021 Loglass Inc. 30# 3. mapの実装をする
@ 2021 Loglass Inc. 31# 3. mapの実装をする自分自身に関数を適用さっきの 「1 -> “あ”」の関数
@ 2021 Loglass Inc. 32# 3. mapの実装をする子供全員に再帰関数を適用する
@ 2021 Loglass Inc. 33できた!
@ 2021 Loglass Inc. 34全体像
@ 2021 Loglass Inc. 35FIN
@ 2021 Loglass Inc. 36ではない
@ 2021 Loglass Inc. 37
@ 2021 Loglass Inc. 3810000階層のツリー
@ 2021 Loglass Inc. 39
@ 2021 Loglass Inc. 40スタックオーバーフロー!!!
@ 2021 Loglass Inc. 41# ⚠ここからは尺の関係上ざっくり説明します● 全てを理解しようとしないでください● あ〜こんなやり方あるんだな〜で大丈夫です👍● コードはこちらです○ https://github.com/YuitoSato/kotlin-sandbox/blob/master/src/main/kotlin/tree/Tree.kt
@ 2021 Loglass Inc. 42# 再帰関数におけるスタックオーバーフローとは● 子の計算を全て終えないと親の関数が終わらない○ 計算時の関数内ローカル変数をスタックに保持するが、そこがパンクする
@ 2021 Loglass Inc. 43# では世の中の全ての再帰関数はスタックオーバーフローを起こすの?● 言語によってはNo● 一部の言語には末尾再帰最適化というものが実装されている
@ 2021 Loglass Inc. 44# 末尾再帰最適化 (tail call optimization) とは~ ざっくり説明● 一部のプログラムではビルド時に末尾呼び出しの再帰関数を単なるWhile文に最適化している
@ 2021 Loglass Inc. 45# これは末尾再帰
@ 2021 Loglass Inc. 46# これは末尾再帰ではない最後に評価される関数はTreeのコンストラクタ
@ 2021 Loglass Inc. 47別のやり方でやろう
@ 2021 Loglass Inc. 48最適化が使えないので自力Whileをする
@ 2021 Loglass Inc. 49# map処理のおさらい12 435 6
@ 2021 Loglass Inc. 50# map処理のおさらいあ2 435 6
@ 2021 Loglass Inc. 51# map処理のおさらいあい 435 6
@ 2021 Loglass Inc. 52# map処理のおさらいあい 4う5 6
@ 2021 Loglass Inc. 53# map処理のおさらいあい えう5 6
@ 2021 Loglass Inc. 54# map処理のおさらいあい えうお 6
@ 2021 Loglass Inc. 55幅優先探索だ!💡
@ 2021 Loglass Inc. 56# 幅優先探索にはキュー(先に入れたものが先に出る)を使う12 435 6処理待ちノードを入れるキュー優先処理1
@ 2021 Loglass Inc. 57# 幅優先探索にはキュー(先に入れたものが先に出る)を使うあ2 435 6処理待ちノードを入れるキュー優先処理2341
@ 2021 Loglass Inc. 58# 幅優先探索にはキュー(先に入れたものが先に出る)を使うあい 435 6処理待ちノードを入れるキュー優先処理34562
@ 2021 Loglass Inc. 59# こう実装してみます
@ 2021 Loglass Inc. 60# こう実装してみますキューと最終的に返すツリーの初期化。
@ 2021 Loglass Inc. 61# こう実装してみますキューから取り出して関数を適用
@ 2021 Loglass Inc. 62# こう実装してみます処理したノードを最終的なツリーに足す
@ 2021 Loglass Inc. 63# こう実装してみます次に処理されるノード(子供)をキューにいれる
@ 2021 Loglass Inc. 64# こう実装してみます最後にリターン
@ 2021 Loglass Inc. 65# イメージ: ① キューと空のツリーを用意する12 435 6
@ 2021 Loglass Inc. 66# イメージ: ② キューに積む12 435 61
@ 2021 Loglass Inc. 67# イメージ: ③ キューの先頭に関数を適用する12 435 6あ
@ 2021 Loglass Inc. 68# イメージ: ④ キューの先頭を最終的なツリーに追加する12 435 6あ
@ 2021 Loglass Inc. 69# イメージ: ④ 子供を全てキューに積む12 435 6あ234
@ 2021 Loglass Inc. 70# イメージ: ①~④を繰り返す12 435 6あい えうお か
@ 2021 Loglass Inc. 71できた!(強引)
@ 2021 Loglass Inc. 72今回のコードはこちらに全てあります。https://github.com/YuitoSato/kotlin-sandbox/blob/master/src/main/kotlin/tree/Tree.kt
@ 2021 Loglass Inc. 73# まとめ→ 世の中にツリーは多い→ ツリーのデータ変換は再帰関数が多くてつらい→ map関数を作って再帰処理を隠蔽する→ と思ったらスタックオーバーフローしてしまった→ スタックオーバーフローを回避するために幅優先探索で実装する→ ハッピー!
@ 2021 Loglass Inc. 74ハッピー!(強引)
@ 2021 Loglass Inc. 75# 余談: Q. スタックオーバーフローってどれくらいで起きるの? 🤔A. 手元のマシンで試したら10000階層くらいで発生した(※JVM内で格納しているスタックの量に寄ります)
@ 2021 Loglass Inc. 76# 余談: Q. Loglassってそんな階層の深いツリーを扱うの?🤔A. 扱いません
@ 2021 Loglass Inc. 77# 余談: Q. え、じゃあ幅優先探索の実装とか、必要、、?A. 要りません
@ 2021 Loglass Inc. 78結論: ほぼほぼ再帰処理実装でOK(オチです)
@ 2021 Loglass Inc. 79ありがとうございました!Kotlinで複雑なデータ構造に立ち向かいたい人Welcomeです!