web-dev-qa-db-ja.com

PHP階層配列-親と子

私はPHPとmySQL with Idiorm を使用しています。それは関係ないかもしれません。

My PHP array

  • 親子の関係ですね。
  • 0はルートの親です。
  • 例:ルートの親0には子33があり、子27には子71があります。

この配列構造は、問題を解決するために必要に応じて変更できます。

array (
  33 => 
    array (
      0 => '27',
      1 => '41',
  ),
  27 => 
    array (
      0 => '64',
      1 => '71',
  ),
  0 => 
    array (
      0 => '28',
      1 => '29',
      2 => '33',
  ),
)

私の階層的な結果

このようなものですが、配列として...

  0 => 
      28
      29
      33
         27 =>
               64
               71
         41

情報

  • 深さは不明であり、無制限にすることができます。私はforeachを試みましたが、それは方法ではないかもしれません。

自分の考え

  • いくつかの再帰的な関数ですか?
  • いくつかのwhileループ?

上記の両方を試しましたが、混乱しました。それはブレーナーです。

23
Jens Törnell

@decezeによる提案が機能しました。ただし、入力配列は次のように少し変更する必要があります...

$rows = array(
    array(
        'id' => 33,
        'parent_id' => 0,
    ),
    array(
        'id' => 34,
        'parent_id' => 0,
    ),
    array(
        'id' => 27,
        'parent_id' => 33,
    ),
    array(
        'id' => 17,
        'parent_id' => 27,
    ),
);

https://stackoverflow.com/a/8587437/476 から:

function buildTree(array $elements, $parentId = 0) {
    $branch = array();

    foreach ($elements as $element) {
        if ($element['parent_id'] == $parentId) {
            $children = buildTree($elements, $element['id']);
            if ($children) {
                $element['children'] = $children;
            }
            $branch[] = $element;
        }
    }

    return $branch;
}

$tree = buildTree($rows);

print_r( $tree );
56
Jens Törnell

@JensTörnellの回答に追加して、parent_idの列名、子の配列キー名、およびidの列名のオプションを定義できるようにしました。

/**
 * function buildTree
 * @param array $elements
 * @param array $options['parent_id_column_name', 'children_key_name', 'id_column_name'] 
 * @param int $parentId
 * @return array
 */
function buildTree(array $elements, $options = [
    'parent_id_column_name' => 'parent_id',
    'children_key_name' => 'children',
    'id_column_name' => 'id'], $parentId = 0)
    {
    $branch = array();
    foreach ($elements as $element) {
        if ($element[$options['parent_id_column_name']] == $parentId) {
            $children = buildTree($elements, $options, $element[$options['id_column_name']]);
            if ($children) {
                $element[$options['children_key_name']] = $children;
            }
            $branch[] = $element;
        }
    }
    return $branch;
}

機能はかなりniversalなので、ほとんどのプロジェクトで上記の関数を使用できました。

7
Fariz Luqman

@JensTörnellからの素晴らしい答えは、parent_idとidが実際に数値ではなく文字列である場合、上記のメソッドは失敗し、子の配列を作成した後、それらの子の配列を個別の個別の配列として再び作成するというわずかな改善を追加したかっただけです。これを修正するには、トリプルイコールチェックを実行する必要があり、変数のデータタイプ(文字列)を比較して指示する必要があります。

文字列ベースのIDと配列のParent_idの場合

function buildTree(array $elements, $parentId = 0) {
    $branch = array();

    foreach ($elements as $element) {
        if ((string)$element['parent_id']  === (string)$parentId) {
            $children = buildTree($elements, $element['id']);
            if ($children) {
                $element['children'] = $children;
            }
            $branch[] = $element;
        }
    }

    return $branch;
}

さらに、必要に応じて、関数に3番目のパラメーターを追加して、変数のデータ型を動的に指定することもできます。つまり、function buildTree(array $elements, $parentId = 0, $datatype='string')ですが、他のエラーが発生する必要があります。

それが誰かを助けることを願っています!

3
Danish
public function createTree (&$list, $parentId = null) {
    $tree = array();
    foreach ($list as $key => $eachNode) {
        if ($eachNode['parentId'] == $parentId) {
            $eachNode['children'] = $this->createTree ($list,$eachNode['id']);
            $tree[] = $eachNode;
            unset($list[$key]);
        }
    }
    return $tree;
}

その関数で連想配列を渡し、最も親がnullでない場合は、最も親のIDを2番目の引数として渡します。

0
Asad Iftikhar