質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Q&A

解決済

2回答

1301閲覧

【設計】都道府県〜市区町村まで含む膨大なステートをイミュータブルなクラスとして設計したい

masamune__

総合スコア1

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

0グッド

3クリップ

投稿2022/11/18 10:16

編集2022/11/18 12:57

前提

初めまして。よろしくお願いいたします。
(モダンな言語であれば)言語に依らない内容だとは思うのですが、
Flutter(Dart)でRiverpodを使い、状態管理を行うという場面を想定しています。
RiverpodはFlutterで状態管理、通知、UI更新を行ってくれるパッケージです。

実現したいこと

関東、関西などの9つのエリアにそれぞれ都道府県があり、
さらにその都道府県の下に市区町村、市が政令指定都市であれば行政区、
といったコレクションを作成し、状態管理を行いたいです。

リストとして表示を行い、各項目を選択することが出来ます。
子を持つ要素に関してはアコーディオンで表示・非表示を切り替える機能を持ちます。

また、子が全て選択された場合は子の選択を全て外して親を選択する、
親を選択した場合は子の選択をすべて外す、などの処理を入れます。

それぞれが選択されているか、アコーディオンが開いているか、などの情報を持たせて、
それをもとに表示を構築します。

発生している問題・エラーメッセージ

上記のようなコレクションを構築する場合、自分が考えた方法ですと、

エリア、都道府県、市区町村、行政区のクラスを作成する、(AreaState、PrefStateのようなイメージ)
エリアのリストを作成する、(List<AreaState> areaStatesのようなイメージ)
そのエリアに入る都道府県リストを作成しエリアと紐づける、(AreaState.prefStatesのようなイメージ)
その都道府県に・・・以下続きます。

dart

1class AreaState { 2 const AreaState({ 3 required this.id, 4 required this.name, 5 required this.prefStates, 6 this.isSelected = false, 7 this.isOpened = false, 8 }); 9 10 final int id; 11 final String name; 12 final List<PrefState> prefStates; 13 final bool isSelected; 14 final bool isOpened; 15}

といった具合に、どんどん入れ子にしていくのが(親からたどりやすいので)管理が簡単かなと思いました。
しかし、考えていくうちにこれでは無理では、と思い始めました。

Riverpodでステート管理を行う場合、ステートはイミュータブルである必要があります。
ステート更新には毎回インスタンスを再生成する必要がある
(state[0].isSelected = true みたいなことは出来ない)のですが、
そうなると入れ子構造では、最下層の更新ですらステートを再構築しなければいけませんでした。

試しにコードも書いてみましたが、子から親を参照し、値を変えられないので
毎回トップのエリアからforを回してifで判定せざるを得ないような感じです。

このような状態管理、機能を実装したい場合、どのような設計にするのがスマートでしょうか?
ご回答、またおかしな部分があればご指摘お願いいたします。

プログラミングというより、アルゴリズムの質問となります。
まともにコードを掲載できなくて申し訳ございません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moriman

2022/11/18 14:30

具体的に何が無理だと考えていますか? 無理だと思うような現象が実際発生しているんですかね? 例えば実際動かしてみて時間がかかり過ぎている、アプリが重い、みたいなことですか? 質問で示されている方法はかなりオーソドックスな方法に見えるのですが、その方法は「スマートではない設計」ということになるんですかね? 「どのような設計がスマートか」は「スマートな設計」の定義によると思いますが、 どんな定義を想定していますか? 一般的にスマートな設計とされている設計方法を知りたい、みたいなことですか? アルゴリズム的に良い結果(速度?)が出るような方法を求めている、みたいなことですか? データ設計というよりも最適な検索方法のアルゴリズムが知りたい、ということですかね? データ構造は情報の性質上必然的に入れ子というか親子関係になるでしょうから、選択肢はあまり多くないような気がします。
masamune__

2022/11/19 02:01

無理、というのは表現がおかしかったかもしれません。 最終的に3つか4つのステートリストが入れ子になりますが、最下層のWardStateを変更する場合、 関数に4つのステートのIDなりを渡して、コピーした親ステートを頭からforで回してifで判定する、 という方法しか思いつかず、なんだか愚直すぎるなと思った次第です。 処理を書くのも大変ですし、 私の考えた方法だと1つのステートを変更するのに最大で2000回近いループをする必要があるので、 どうしてもスマートではない、無駄だと感じてしまいました。 どちらかといえば、最適な検索方法が知りたいといった感じでしょうか?
guest

回答2

0

ベストアンサー

イミュータブルは深いネストのデータ構造と相性が悪いような気がします。

ネストの深いデータ構造を避けて正規化されたMapで実装してみるといいかもしれません。
階層構造は親がList<Id>型のプロパティを持つことで表現する感じで。

詳しくはRDBによる木構造の表現について調べてみるといいと思います。

投稿2022/11/27 11:05

編集2022/11/27 11:15
Aqt

総合スコア27

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

masamune__

2022/11/28 00:34

ご回答ありがとうございます! やはり直接階層になっているとイミュータブルにはしづらいですよね。 各層で個別にステートを持つという発想に至れていませんでした。
guest

0

市町村合併など住所が変わることが多いので、自力でデータを入力して維持するのは時間的コスト的に無理でしょう。
郵便番号データダウンロード

全国地方公共団体コード
をデータベースのテーブルに取り込んで使うのが一般的かと。

投稿2022/11/18 16:03

Orlofsky

総合スコア16415

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

masamune__

2022/11/19 02:06

質問から分かりにくくて申し訳ありません。 上記のようなデータを準備し、それをアプリで使う際に 県と市を親子関係にしたり、選択状態やアコーディオンの開閉状態を管理するために加工します。 そのときのスマートな構築方法、ないし最下層の情報に簡単にアクセスする方法を知りたい、というのが質問内容です。
masamune__

2022/11/19 17:44

状態管理ではなく、SQLiteなどでアプリ内にデータベースの形式で落とし込んで、 データベース操作で対応するのがいい、ということでしょうか?
Orlofsky

2022/11/19 21:10

SQLiteは2000年に当時の非力かPCで稼働できる無料のデータベースとしてSQLの機能を削って載せたものです。システムが複雑になった時の対応が難しいかもしれないので、最初からMySQLやMariaDBを使われては?
masamune__

2022/11/20 05:11

選択状態や開閉状態は共有ではありません。 個別かつアプリを閉じると初期化されます。(ですので状態管理を使うつもりでした。) サーバ側のデータベースで管理する場合、 アプリが起動するごとにアプリの数だけデータを増やす必要がありそうですが そのあたりはどう実装するのでしょうか?
Orlofsky

2022/11/20 07:33

わたしはOracle Express Edition for WindowsをインストールすたWindows10 Professional 64bitを1台で自宅で開発しています。MySQLやMariaDBも同じように使えます。ご参考に。
masamune__

2022/11/20 09:32

えーっと、話がすれ違っているように感じるのですが。 Flutterと書いたので伝わっているとは思いますが、 開発しているのはスマートフォンアプリで、アプリはスマホ上で動きます。 データベースを置けるのはユーザーのスマホ内か、APIを構築しているサーバになると思います。 サーバ側のデータベースで対応する場合、アプリからのアクセスごとに状態管理が必要なので アプリへの初回アクセス時に都道府県データをコピーする必要があると思いますが、 約2,000件のデータをユーザーごとに生成するのは、非常に無駄に感じますし非効率的に思います。 そのあたりはどう実装するのがいいのでしょうか?というのが上記の返信です。
reinohito

2022/11/21 04:21

> 時間的コスト的に無理でしょう。 時間的制約についてもコスト的制約についても何一つ語られていないのに、 なんか、話が噛み合って進展してるの、 なんでだろ~? こちらには読めない文字で付帯条件とか どっかに書いてあるのかな~?
reinohito

2022/11/21 04:23

> それぞれが選択されているか、アコーディオンが開いているか、などの情報を持たせて、 > それをもとに表示を構築します。 表示のステートなんか、いかようにもなる話でどうでもいい事語られても なんでだろ~?
masamune__

2022/11/21 05:05

> なんか、話が噛み合って進展してるの、 こちらとしては最初から噛み合ってないと思ってましたが。 自分の知識不足故、こういう場合は状態管理よりデータベースで管理するのかもしれないと思い、 コメントをしておりました。 > 表示のステートなんか、いかようにもなる話でどうでもいい事語られても 如何ようにもなる、の手段があまり分かっていないので質問しております。 質問文にもありますが、すべて親子関係でList<AreaState> areaStatesを更新していく場合、 最下層のwardStatesに到達するまでに何度も条件分岐を挟む必要があるので あまりスマートではないな、と思っている次第です。 そもそもの組み方が悪いのであれば、そのアドバイスが頂ければと思います。 よろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問