7370
元データhogeAry  
・子に対する親を parent_id で指定  
・親は parent_id = 0

```

    Array
    (
        [0] => Array
            (
                [hoge_id] => 2
                [hoge] => 親2
                [parent_id] => 0
            )
        [1] => Array
            (
                [hoge_id] => 3
                [hoge] => 子2-1
                [parent_id] => 2
            )
        [2] => Array
            (
                [hoge_id] => 4
                [hoge] => 子7-1
                [parent_id] => 7
            )
        [3] => Array
            (
                [hoge_id] => 7
                [hoge] => 親7
                [parent_id] => 0
            )
        [4] => Array
            (
                [hoge_id] => 1
                [hoge] => 親1
                [parent_id] => 0
            )
     )
    
```

希望出力結果

```

    <ul>
      <li>親1</li>
      <li>親2
        <ul>
          <li>子2-1</li>
        </ul>
      </li>
      <li>親7
        <ul>
          <li>子7-1</li>
        </ul>
      </li>
    </ul>
    
```
CC BY-SA 3.0
2015-03-03T01:25:16.077
7341
2015-03-03T08:08:32.537
2015-03-03T03:46:22.523
7926
7886
question
php html
PHP多次元配列から階層リストタグ<ul><li></li><li><ul><li></li></ul></li></ul>を出力したい
現状で細かい条件などが示されていないので、とりあえず例示されているデータでちゃんと出来るように適当に組んでみました。  
`$data` に例示された配列としてみてください。

```

    /**
     * hoge_id を比較して昇順にする.
     * @param array $a 左辺
     * @param array $b 右辺
     * @return integer $a['hoge_id'] が $b より大きい時は 1. $b['hoge_id'] が $a 以下の時は -1 を返す.
     */
    function id_cmp( array $a, array $b )
    {
        return ($a['hoge_id']>$b['hoge_id']) ? 1 : -1;
    }
    // リストデータ作成.
    $listed_data = array();
    foreach( $data as $datum )
    {
        // もしなんかの親だったら子供を探す
        if( $datum['parent_id'] === 0 ) {
            foreach( $data as $_child_datum ) {
                // 子を見つけたら子として拾っておく
                if( $datum['hoge_id'] == $_child_datum['parent_id'] ) {
                    $datum['childs'] []= $_child_datum;
                }
            }
            $listed_data []= $datum;
        }
    }
    // hoge_id 順にソート.
    usort($listed_data,'id_cmp');
    
    // リスト化開始.
    $buffer='<ul>';
    foreach( $listed_data as $datum ) {
        $buffer.="<li>{$datum['hoge']}";
        if( isset($datum['childs']) ) {
            $buffer.='<ul>';
            $childs = $datum['childs'];
            foreach( $childs as $child ) {
                $buffer.="<li>{$child['hoge']}</li>";
            }
            $buffer.='</ul></li>';
        } else {
            $buffer.='</li>';
        }
    }
    // リスト表示.
    echo $buffer.='</ul>';
    
```

使い捨てコードなので汚くて済みません。  
目的も他のデータパターンがあるのかどうか分かりませんでしたがこれでいかがでしょうか？
CC BY-SA 3.0
2015-03-03T04:32:53.170
7352
2015-03-03T04:32:53.170
7926
7341
answer
宿題を手伝っている感じがしますが…  
オブジェクトを使って、ループ内のコードを簡単にしようとしてます。配列に比べると、オブジェクトだと持ち回しができるのでコードの見通しが良くなると思っています。その代わりHTML変換で再帰呼び出しになってしまいました。

ざっと書いただけなので、ちゃんと書くなら、  
・stdClassではなくてHoge用のクラスを使う、  
・エラー処理を行う、  
など必要なことはたくさんありそうです。

```

    // オブジェクトに変換する
    $hogeAll = [];
    foreach($data as $hoge) {
        $hogeAll[$hoge['hoge_id']] = makeHoge($hoge);
    }
    // 階層構造を構築する
    $root = [];
    foreach($hogeAll as $hoge) {
        if($hoge->parent>0) {
            $hogeAll[$hoge->parent]->children[] = $hoge;
        } else {
            $root[] = $hoge;
        }
    }
    // HTMLに変換する
    echo listHoge($root);
    
    /**
     * @param stdClass[] $hogeList
     * @param string     $head
     * @return string
     */
    function listHoge(array $hogeList, $head='') {
        $string = "{$head}<ul>";
        foreach($hogeList as $hoge) {
            $string .= "\n{$head}  <li>".$hoge->val;
            if($hoge->children) {
                $string .= "\n{$head}  ".listHoge($hoge->children, "{$head}  ")."\n{$head}";
            }
            $string .= "</li>";
        }
        return $string."\n{$head}</ul>";
    }
    
    /**
     * @param array $data
     * @return stdClass
     */
    function makeHoge($data) {
        $hoge           = new stdClass();
        $hoge->id       = $data['hoge_id'];
        $hoge->val      = $data['hoge'];
        $hoge->parent   = $data['parent_id'];
        $hoge->children = [];
        return $hoge;
    }
    
```
CC BY-SA 3.0
2015-03-03T06:18:32.670
7361
2015-03-03T06:37:04.553
2015-03-03T06:37:04.553
2571
2571
7341
answer
他の方のアプローチのように、表示したい構造に合わせた木構造に変換してから表示用の組み立て処理を行うのも手ですが、今回示されているデータはある意味すでに木構造を表していますので、わざわざ表示向けのデータ構造に変換しないアプローチでもよいかと思います。

下のコードでは、基本的な再帰のアプローチで、都度対象となる子を抽出してきてタグを組み立てています。

```

    <?php
    
    $data = [
        [
            'hoge_id' => 2,
            'hoge' => '親2',
            'parent_id' => 0,
        ],
        [
            'hoge_id' => 8,
            'hoge' => '孫',
            'parent_id' => 4,
        ],
        [
            'hoge_id' => 3,
            'hoge' => '子2-1',
            'parent_id' => 2,
        ],
        [
            'hoge_id' => 4,
            'hoge' => '子7-1',
            'parent_id' => 7,
        ],
        [
            'hoge_id' => 7,
            'hoge' => '親7',
            'parent_id' => 0,
        ],
        [
            'hoge_id' => 1,
            'hoge' => '親1',
            'parent_id' => 0,
        ]
    ];
    
    class HtmlUlBuilder
    {
        private $data;
    
        public function __construct($data)
        {
            $this->data = $data;
        }
    
        public function buildFromParent($parent_id)
        {
            $children = array_filter($this->data, function ($element) use ($parent_id) {
                return $element['parent_id'] === $parent_id;
            });
    
            if (count($children) === 0) return '';
    
            return '<ul>' . array_reduce($children, function ($current, $element) {
                return $current . PHP_EOL . '<li>' . $element['hoge'] . $this->buildFromParent($element['hoge_id']) . '</li>';
            }, '') . '</ul>';
        }
    }
    
    usort($data, function ($a, $b) {
        return $a['hoge_id'] > $b['hoge_id'];
    });
    
    $builder = new HtmlUlBuilder($data);
    $html = $builder->buildFromParent(0);
    
    echo $html;
    
```
CC BY-SA 3.0
2015-03-03T08:08:32.537
7370
2015-03-03T08:08:32.537
5444
7341
answer