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

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

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

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

2回答

315閲覧

PHPでフラットな配列を木構造に変換した際に経路を残したい

Mi-ko

総合スコア9

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2022/11/22 11:12

編集2022/11/22 12:50

実現したいこと

PHPでフラットな配列を木構造に変換した際に経路を残したいです。
配列から木構造に変換はできたのですがキーのlistとして残す部分の処理が分かりません。

該当のソースコード

// 変換前 [ 'id' => 1, 'parent_id' => null ], [ 'id' => 2, 'parent_id' => 1 ], [ 'id' => 3, 'parent_id' => 1 ], [ 'id' => 4, 'parent_id' => 3 ], [ 'id' => 5, 'parent_id' => null ], [ 'id' => 6, 'parent_id' => 5 ], [ 'id' => 7, 'parent_id' => 6 ]; // 変換後(木構造) [ 'list' => '1', 'id' => 1, 'parent_id' => null, 'children' => [ [ 'list' => '1, 2', 'id' => 2, 'parent_id' => 1 ], [ 'list' => '1, 3', 'id' => 3, 'parent_id' => 1, 'children' => [ 'list' => '1, 3, 4', 'id' => 4, 'parent_id' => 3 ] ], ], [ 'id' => 5, 'parent_id' => null, 'children' => [ [ 'list' => '5, 6', 'id' => 6, 'parent_id' => 5 ], [ 'list' => '5, 7', 'id' => 7, 'parent_id' => 6 ] ] ], ];

試したこと

・親をみて足していく
・マップを作って参照する
他にもいろいろ試してはみましたがそもそものフラットな配列から木構造の変換の時点でもう少し何か手を加えないといけないのかもわからずはまっていますのでよろしければお助け下さい。

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

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

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

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

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

guest

回答2

0

ベストアンサー

別解のため回答を分けます。
MySQLで入れ子モデルテスト

(1)サンプルテーブル作成

SQL

1create table tree ( 2id int not null unique, 3parent_id int, 4level int not null default 0, 5l int not null default 0, 6r int not null default 0); 7 8insert into tree(id,parent_id) values 9(1600,NULL),(1700,1600),(1750,1600),(1800,1700),(1820,1700),(1850,1700),(1900,1800);
  • level=何階層目かを計算していれる
  • l=左の値(計算で求める)
  • r=右の値(計算で求める)

(2)procedureの作成

SQL

1drop procedure if exists SET_LR; 2delimiter // 3create procedure SET_LR() 4begin 5declare a int default 0; 6declare done int default 0; 7declare cur cursor FOR 8select id from tree where level=0 order by parent_id asc,id desc; 9declare continue handler for sqlstate '02000' set done = 1; 10update tree set level=0,l=0,r=0; 11update tree set level=1,l=(select @a:=@a+1 from (select @a:=0) AS sub),r=@a:=@a+1 12where parent_id is null 13order by id; 14open cur; 15repeat 16fetch cur into a; 17if not done then 18set @id=a; 19set @sql='update tree as a1,tree as a2,tree as a3 set a1.l=a2.l+1,a1.r=a2.l+2,a1.level=a2.level+1,a2.r=a2.r+2,a3.r=a3.r+2 where a1.parent_id=a2.id and a2.l<a3.r and a1.id=?'; 20prepare stmt from @sql; 21execute stmt using @id; 22set @sql='update tree as a1,tree as a2,tree as a3 set a3.l=a3.l+2 where a1.parent_id=a2.id and a2.l<a3.l and a3.id!=a1.id and a1.id=?'; 23prepare stmt from @sql; 24execute stmt using @id; 25end if; 26until done end repeat; 27close cur; 28end 29// 30delimiter ;

(3)procedureの実行
※実際にはデータを追加・更新・削除するたびに実行する

SQL

1call SET_LR();

テスト

(1)単純なデータ

SQL

1select * from tree;
idparent_idlevellr
1600NULL1114
170016002211
1750160021213
18001700336
18201700378
185017003910
19001800445

(2)階層表示

SQL

1select CONCAT( REPEAT( "__", LEVEL -1 ) , id ) AS id 2from tree 3order by l;
id
1600
__1700
____1800
______1900
____1820
____1850
__1750

(3)経路表示

SQL

1select t2.id,group_concat(t1.id order by t1.parent_id asc) as route 2from tree as t1 3inner join tree as t2 4on t2.l between t1.l and t1.r 5group by t2.id;
idroute
16001600
17001600,1700
17501600,1750
18001600,1700,1800
18201600,1700,1820
18501600,1700,1850
19001600,1700,1800,1900

投稿2022/11/22 13:39

yambejp

総合スコア114784

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

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

0

なんとなく条件が曖昧ですが

PHP

1$a=[ 2 "1700" => [ 3 "to_id" => 1700, 4 "from_id" => 1600, 5 ], 6 "1800" => [ 7 "to_id" => 1800, 8 "from_id" => 1700, 9 ], 10 "1900" => [ 11 "to_id" => 1900, 12 "from_id" => 1800, 13 ], 14 ]; 15 16foreach($a as $key=>&$vals){ 17 $vals["list"]=(isset($a[$from=$vals["from_id"]])?$a[$from]["list"]:$vals["from_id"]).",".$vals["to_id"]; 18} 19print_r($a);

ただしPHPの配列はキーが必ずしも若い順(命題でいう経路順)で格納されているわけではないので、
キーの順番が変わった場合に正しく経路が抜き出せません。
予めfrom_idでソートをしてから処理をする必要があるかもしれません

投稿2022/11/22 11:25

編集2022/11/22 11:27
yambejp

総合スコア114784

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

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

Mi-ko

2022/11/22 11:29

申し訳ありません。記載ミスをしていました。 木構造にしたデータに対して経路を保存したいと言う趣旨の質問でした。
yambejp

2022/11/22 11:57 編集

ちょっと曖昧な部分が多すぎるのでもう少しだけサンプル数(どういうデータからどういう木構造をつくりたいか)を増やせませんか?(たとえば分岐しないのかとか)
yambejp

2022/11/22 12:00

ちなみにこの手の処理はDBを利用し、 親情報だけをもつ「隣接リスト」から「入れ子集合モデル」にプロシージャで変換して管理するとわかりやすくなります。
Mi-ko

2022/11/22 13:08

サンプル変更させて頂きました。 変換前から変換後のデータに変更したいです。 入れ子集合モデルは勉強したことないので調べてみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問