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

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

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

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

アルゴリズム

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

Q&A

解決済

3回答

594閲覧

再帰処理のアルゴリズム

owqbpu

総合スコア13

PHP

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

アルゴリズム

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

0グッド

1クリップ

投稿2017/06/27 06:41

編集2017/06/27 07:57

###前提・実現したいこと
PHP初心者です。
一次元の配列から、階層構造の配列を作成したいのですが再帰処理を使用したことがなく、うまく出来ずにいます。

元データから、2つの結果を導きたいです。
導き出した配列はメニュー用に表示したりして使おうと思っています。

わかりやすい方法、短く書くことが出来る方法、やテクニカルな方法など色々な形を見たいです。
もしくは、結果の構造はこっちのほうが良いよ、などのアドバイスなどもあれば是非聞きたいです。
(元はparentなのにchildrenを作ろうとしていることに少し違和感があります)

よろしくお願いします!

PHP

1// 元データ 2$original = [ 3 // id, 親id, 名前 4 ['id' => 1, 'parent' => 0, 'name' => 'aaaa'], 5 ['id' => 2, 'parent' => 0, 'name' => 'bbbb'], 6 ['id' => 3, 'parent' => 1, 'name' => 'cccc'], 7 ['id' => 4, 'parent' => 2, 'name' => 'dddd'], 8 ['id' => 5, 'parent' => 3, 'name' => 'eeee'], 9];

PHP

1// 1つ目はこの結果が欲しい 2$result1 = [ 3 1 => [ 4 'catname' => 'aaaa', // 名前を連結する 5 'name' => 'aaaa', 6 'children' => [ 7 3 => [ 8 'catname' => 'aaaa cccc', 9 'name' => 'cccc', 10 'children' => [ 11 5 => [ 12 'catname' => 'aaaa cccc eeee', 13 'name' => 'eeee', 14 'children' => [], 15 ], 16 ], 17 ], 18 ], 19 ], 20 2 => [ 21 'catname' => 'bbbb', 22 'name' => 'bbbb', 23 'children' => [ 24 4 => [ 25 'catname' => 'bbbb dddd', 26 'name' => 'dddd', 27 'children' => [], 28 ], 29 ], 30 ], 31];

PHP

1 2// 2つ目はこの結果が欲しい 3$result2 = [ 4 1 => 'aaaa', 5 2 => 'bbbb', 6 3 => 'aaaa cccc', 7 4 => 'bbbb dddd', 8 5 => 'aaaa cccc eeee', 9]; 10

追記

@mts10806さん

途中のソース

半端ですがこちらです。id => 5が出来ていません。また、catnameも出来ていません。
引数の参照渡しについて今ひとつ理解できていませんが、これがわかりにくくさせてる気もしています。
再帰処理は参照渡しが必要になってしまうものですか?returnで返したほうがわかりやすい気がしています。
子要素を作る処理が2回出てきている('children' => []を2箇所でしてる)ので、何か違うなとも思っています。

PHP

1 2function recursive(&$result, $array) { 3 if ($array['parent'] === 0) { 4 $result[$array['id']] = [ 5 'name' => $array['name'], 6 'children' => [], 7 ]; 8 } else { 9 if (isset($result[$array['parent']])) { 10 $result[$array['parent']]['children'][$array['id']] = [ 11 'name' => $array['name'], 12 'children' => [], 13 ]; 14 } else { 15 foreach ($result as $array2) { 16 recursive($array2['children'], $array['parent']); 17 } 18 } 19 } 20} 21 22$original = [ 23 ['id' => 1, 'parent' => 0, 'name' => 'aaaa'], 24 ['id' => 2, 'parent' => 0, 'name' => 'bbbb'], 25 ['id' => 3, 'parent' => 1, 'name' => 'cccc'], 26 ['id' => 4, 'parent' => 2, 'name' => 'dddd'], 27 ['id' => 5, 'parent' => 3, 'name' => 'eeee'], 28]; 29 30$result = []; 31foreach ($original as $array) { 32 recursive($result, $array); 33} 34var_dump($result); 35

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

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

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

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

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

yambejp

2017/06/27 06:44

子供の配列はかならずparentの配列の後に出現すると担保されていますか?
owqbpu

2017/06/27 06:50

はい。['id' => 6, 'parent' => 7, 'name' => 'ffff'], ['id' => 7, 'parent' => 0, 'name' => 'gggg'], の様なものはなく、絶対にparentが先に存在します。
m.ts10806

2017/06/27 06:51

「うまく出来ずに」とのことなので苦労して組まれている途中のソースがあるかと思います。そのソースからアドバイスをもらえることもあるので、現在組まれているソースのご提示もお願いします。
owqbpu

2017/06/27 06:53

parentが先に存在しない場合の方法も可能であれば見たいです。
guest

回答3

0

ちょっとゴテゴテしてて申し訳ないです。

php

1<?php 2function recursive($source, &$result1, &$result2, $parent, $categories = []) { 3 foreach ($source as $s) { 4 if ($s['parent'] == $parent) { 5 $new_categories = array_merge($categories, [$s['name']]); 6 $id = $s['id']; 7 $category = implode(' ',$new_categories); 8 $result1[$id] = [ 9 'catname' => $category, 10 'name' => $s['name'], 11 'children' => [] 12 ]; 13 $result2[$id] = $category; 14 recursive($source, $result1[$id]['children'],$result2,$id,$new_categories); 15 } 16 } 17} 18 19$original = [ 20 ['id' => 1, 'parent' => 0, 'name' => 'aaaa'], 21 ['id' => 2, 'parent' => 0, 'name' => 'bbbb'], 22 ['id' => 3, 'parent' => 1, 'name' => 'cccc'], 23 ['id' => 4, 'parent' => 2, 'name' => 'dddd'], 24 ['id' => 5, 'parent' => 3, 'name' => 'eeee'], 25]; 26 27$result1 = []; 28$result2 = []; 29recursive($original, $result1, $result2, 0); 30ksort($result2); 31var_dump($result1); 32var_dump($result2);

結果

array(2) { [1]=> array(3) { ["catname"]=> string(4) "aaaa" ["name"]=> string(4) "aaaa" ["children"]=> array(1) { [3]=> array(3) { ["catname"]=> string(9) "aaaa cccc" ["name"]=> string(4) "cccc" ["children"]=> array(1) { [5]=> array(3) { ["catname"]=> string(14) "aaaa cccc eeee" ["name"]=> string(4) "eeee" ["children"]=> array(0) { } } } } } } [2]=> array(3) { ["catname"]=> string(4) "bbbb" ["name"]=> string(4) "bbbb" ["children"]=> array(1) { [4]=> array(3) { ["catname"]=> string(9) "bbbb dddd" ["name"]=> string(4) "dddd" ["children"]=> array(0) { } } } } } array(5) { [1]=> string(4) "aaaa" [2]=> string(4) "bbbb" [3]=> string(9) "aaaa cccc" [4]=> string(9) "bbbb dddd" [5]=> string(14) "aaaa cccc eeee" } ```result2がどうしてもキー順にならないので、関数外でソートしてあげないとダメです。 なかなか面白かったです。

投稿2017/06/27 08:44

編集2017/06/27 09:07
shi_ue

総合スコア4437

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

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

0

ベストアンサー

再帰で配列を使うとリファレンスが必要なので理解しづらいですね。

$headで定義したようにダミーの親を作ると短く書けるようになると思います。
print_r($head)すると0の下に全て追加されているのがわかります。

php

1<?php 2function transform(&$parent, $parentId, $catname, &$item) { 3 if ($parentId == $item['parent']) { 4 $parent['children'][$item['id']] = [ 5 'catname' => $catname . " " . $item['name'], 6 'name' => $item['name'], 7 'children' => [], 8 ]; 9 return; 10 } 11 12 foreach ($parent['children'] as $id => &$child) { 13 transform($child, $id, $catname . " " . $child['name'], $item); 14 } 15} 16 17function categories($node) 18{ 19 $cats = []; 20 foreach ($node['children'] as $id => $child) { 21 $cats[$id] = $child['catname']; 22 $cats = $cats + categories($child); 23 } 24 ksort($cats); 25 return $cats; 26} 27 28$original = [ 29 // id, 親id, 名前 30 ['id' => 1, 'parent' => 0, 'name' => 'aaaa'], 31 ['id' => 2, 'parent' => 0, 'name' => 'bbbb'], 32 ['id' => 3, 'parent' => 1, 'name' => 'cccc'], 33 ['id' => 4, 'parent' => 2, 'name' => 'dddd'], 34 ['id' => 5, 'parent' => 3, 'name' => 'eeee'], 35]; 36 37// $result1 38$head = ['children' => []]; 39foreach ($original as &$item) { 40 transform($head, 0, '', $item); 41} 42print_r($head['children']); 43 44// $result2 45print_r(categories($head));

php

1Array 2( 3 [1] => Array 4 ( 5 [catname] => aaaa 6 [name] => aaaa 7 [children] => Array 8 ( 9 [3] => Array 10 ( 11 [catname] => aaaa cccc 12 [name] => cccc 13 [children] => Array 14 ( 15 [5] => Array 16 ( 17 [catname] => aaaa cccc eeee 18 [name] => eeee 19 [children] => Array 20 ( 21 ) 22 23 ) 24 25 ) 26 27 ) 28 29 ) 30 31 ) 32 33 [2] => Array 34 ( 35 [catname] => bbbb 36 [name] => bbbb 37 [children] => Array 38 ( 39 [4] => Array 40 ( 41 [catname] => bbbb dddd 42 [name] => dddd 43 [children] => Array 44 ( 45 ) 46 47 ) 48 49 ) 50 51 ) 52 53) 54Array 55( 56 [1] => aaaa 57 [2] => bbbb 58 [3] => aaaa cccc 59 [4] => bbbb dddd 60 [5] => aaaa cccc eeee 61)

投稿2017/06/27 16:38

kodai

総合スコア759

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

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

owqbpu

2017/06/28 03:28

みなさまありがとうございます。 @kodai さん > $headで定義したようにダミーの親を作る この様な考えが全く無かったので、目からウロコでした!勉強になりました!
guest

0

抽出項目は未調整ですがこんな感じで

PHP

1$a=[ 2 ['id' => 1, 'parent' => 0, 'name' => 'aaaa'], 3 ['id' => 2, 'parent' => 0, 'name' => 'bbbb'], 4 ['id' => 3, 'parent' => 1, 'name' => 'cccc'], 5 ['id' => 4, 'parent' => 2, 'name' => 'dddd'], 6 ['id' => 5, 'parent' => 3, 'name' => 'eeee'], 7 ['id' => 6, 'parent' => 3, 'name' => 'ffff'], 8 ['id' => 7, 'parent' => 1, 'name' => 'gggg'], 9]; 10 11$b=[]; 12foreach(array_reverse($a) as $data){$b[$data["id"]]=$data;} 13foreach($b as $key=>$data){ 14 $p=$data["parent"]; 15 if(!isset($b[$key]["children"])) $b[$key]["children"]=[]; 16 if(array_key_exists($p,$b) ){ 17 if(!isset($b[$p]["children"])) $b[$p]["children"]=[]; 18 $b[$p]["children"]=array_replace([$key=>$b[$key]],$b[$p]["children"]); 19 unset($b[$key]); 20 }else{ 21 $b=array_replace([$key=>$data],$b); 22 } 23} 24print_r($b);

投稿2017/06/27 14:34

yambejp

総合スコア114572

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問