11

重複の可能性:
親 ID 値に基づいて配列を 1 次元から多次元に変換する

私はPHPで働いています。

リレーショナル データ (親子関係) を持つ次の配列があります。

Array        
(        
    [5273] => Array        
        (        
            [id] => 5273        
            [name] => John Doe        
            [parent] =>         
        )        

    [6032] => Array        
        (        
            [id] => 6032        
            [name] => Sally Smith        
            [parent] => 5273        
        )        

    [6034] => Array        
        (        
            [id] => 6034        
            [name] => Mike Jones        
            [parent] => 6032        
        )        

    [6035] => Array        
        (        
            [id] => 6035        
            [name] => Jason Williams        
            [parent] => 6034        
        )        

    [6036] => Array        
        (        
            [id] => 6036        
            [name] => Sara Johnson        
            [parent] => 5273        
        )        

    [6037] => Array        
        (        
            [id] => 6037        
            [name] => Dave Wilson        
            [parent] => 5273        
        )        

    [6038] => Array        
        (        
            [id] => 6038        
            [name] => Amy Martin        
            [parent] => 6037        
        )        
)        

この JSON 形式にする必要があります。

{        
   "id":"5273",        
   "name":"John Doe",        
   "data":{        

   },        
   "children":[        
      {        
         "id":" Sally Smith",        
         "name":"6032",        
         "data":{        

         },        
         "children":[        
            {        
               "id":"6034",        
               "name":"Mike Jones",        
               "data":{        

               },        
               "children":[        
                  {        
                     "id":"6035",        
                     "name":"Jason Williams",        
                     "data":{        

                     },        
                     "children":[        
                        {        
                           "id":"node46",        
                           "name":"4.6",        
                           "data":{        

                           },        
                           "children":[        

                           ]        
                        }        
                     ]        
                  }        
               ]        
            },        
            {        
               "id":"6036",        
               "name":"Sara Johnson",        
               "data":{        

               },        
               "children":[        

               ]        
            },        
            {        
               "id":"6037",        
               "name":"Dave Wilson",        
               "data":{        

               },        
               "children":[        
                  {        
                     "id":"6038",        
                     "name":"Amy Martin",        
                     "data":{        

                     },        
                     "children":[        

                     ]        
                  }        
               ]        
            }        
         ]        
      }        
   ]        
}        

多次元配列を作成し、それを json_encode() で実行する必要があることはわかっています。また、これを行うために使用されるこのメソッドは、再帰的である必要があると考えています。これは、現実世界のデータには不明な数のレベルが含まれる可能性があるためです。

私のアプローチのいくつかを紹介したいと思いますが、うまくいきませんでした。

誰でも私を助けることができますか?

私の作品を共有するように頼まれました。これは私が試したことですが、それほど役に立ちませんでした。

関係だけの配列を作成しました。

foreach($array as $k => $v){
    $relationships[$v['id']] = $v['parent'];
}

(別の SO 投稿に基づいて) このリレーショナル データを使用して、新しい多次元配列を作成したと思います。これが機能するようになったら、正しい「子」ラベルなどを追加することに取り組みました。

$childrenTable = array();
    $data = array();
    foreach ($relationships as $n => $p) {
      //parent was not seen before, put on root
      if (!array_key_exists($p, $childrenTable)) {
          $childrenTable[$p] = array();
          $data[$p] = &$childrenTable[$p];  
      }
      //child was not seen before
      if (!array_key_exists($n, $childrenTable)) {
          $childrenTable[$n] = array();
      }
      //root node has a parent after all, relocate
      if (array_key_exists($n, $data)) {
          unset($data[$n]);
      }
      $childrenTable[$p][$n] = &$childrenTable[$n];      
    }
    unset($childrenTable);

print_r($data);
4

3 に答える 3

15
<?php
header('Content-Type: application/json; charset="utf-8"');

/**
 * Helper function
 * 
 * @param array   $d   flat data, implementing a id/parent id (adjacency list) structure
 * @param mixed   $r   root id, node to return
 * @param string  $pk  parent id index
 * @param string  $k   id index
 * @param string  $c   children index
 * @return array
 */
function makeRecursive($d, $r = 0, $pk = 'parent', $k = 'id', $c = 'children') {
  $m = array();
  foreach ($d as $e) {
    isset($m[$e[$pk]]) ?: $m[$e[$pk]] = array();
    isset($m[$e[$k]]) ?: $m[$e[$k]] = array();
    $m[$e[$pk]][] = array_merge($e, array($c => &$m[$e[$k]]));
  }

  return $m[$r][0]; // remove [0] if there could be more than one root nodes
}

echo json_encode(makeRecursive(array(
  array('id' => 5273, 'parent' => 0,    'name' => 'John Doe'),  
  array('id' => 6032, 'parent' => 5273, 'name' => 'Sally Smith'),
  array('id' => 6034, 'parent' => 6032, 'name' => 'Mike Jones'),
  array('id' => 6035, 'parent' => 6034, 'name' => 'Jason Williams'),
  array('id' => 6036, 'parent' => 5273, 'name' => 'Sara Johnson'),
  array('id' => 6037, 'parent' => 5273, 'name' => 'Dave Wilson'),
  array('id' => 6038, 'parent' => 6037, 'name' => 'Amy Martin'),
)));

デモ: https://3v4l.org/s2PNC

于 2012-06-28T08:14:42.673 に答える
3

わかりました、これがその仕組みです。実際には、開始時にそれほど遠くはありませんでしたが、実際に探しているのは参照です。これは一般的な手順です。

ID には親ノードと子ノードの間に関係があるため、最初に ID に基づいてデータのインデックスを作成する必要があります。ここでは配列 ( $rows) を使用してデータ アクセスをシミュレートします。データベースから読み取る場合も同様です。このインデックスを使用すると、空のデータなどの追加のプロパティを追加することもできます。

// create an index on id
$index = array();
foreach($rows as $row)
{
    $row['data'] = (object) array();
    $index[$row['id']] = $row;
}

そのため、すべてのエントリが ID でインデックス化されます。これが最初のステップでした。

2 番目のステップも同様に簡単です。の ID に基づいて各ノードにアクセスできるようになったため$index、子を親に割り当てることができます。

ID 0 の「仮想」ノードが 1 つあります。これはどの行にも存在しませんが、子も追加できれば、この子コレクションをすべてのルートのストアとして使用できます。あなたの場合、単一のルートノードがあります。

確かに、 ID0については、親を処理すべきではありません - 親が存在しないためです。

では、そうしましょう。ここで参照を使用します。そうしないと、同じノードが親と子の両方になることができないためです。

// build the tree
foreach($index as $id => &$row)
{
    if ($id === 0) continue;
    $parent = $row['parent'];
    $index[$parent]['children'][] = &$row;
}
unset($row);

参照を使用しているため、最後の行は$row、ループの後に格納されている参照を設定解除するように注意しています。

これで、すべての子が親に割り当てられました。すでにそうかもしれませんが、最後のステップを忘れないでください。出力の実際のノードにアクセスする必要があります。

$index簡潔にするために、ルート ノードをそれ自体に割り当てます。思い出すと、必要な唯一のルート ノードは、ID を持つノードの children 配列の最初のノード0です。

// obtain root node
$index = $index[0]['children'][0];

以上です。これをすぐに使用して、JSON を生成できます。

// output json
header('Content-Type: application/json');
echo json_encode($index);

最後にコード全体を一目で:

<?php
/**
 * @link http://stackoverflow.com/questions/11239652/php-create-a-multidimensional-array-from-an-array-with-relational-data
 */

$rows = array(
    array('id' => 5273, 'parent' => 0,    'name' => 'John Doe'),
    array('id' => 6032, 'parent' => 5273, 'name' => 'Sally Smith'),
    array('id' => 6034, 'parent' => 6032, 'name' => 'Mike Jones'),
    array('id' => 6035, 'parent' => 6034, 'name' => 'Jason Williams'),
    array('id' => 6036, 'parent' => 5273, 'name' => 'Sara Johnson'),
    array('id' => 6037, 'parent' => 5273, 'name' => 'Dave Wilson'),
    array('id' => 6038, 'parent' => 6037, 'name' => 'Amy Martin'),
);

// create an index on id
$index = array();
foreach($rows as $row)
{
    $row['data'] = (object) [];
    $index[$row['id']] = $row;
}

// build the tree
foreach($index as $id => &$row)
{
    if ($id === 0) continue;
    $parent = $row['parent'];
    $index[$parent]['children'][] = &$row;
}
unset($row);

// obtain root node
$index = $index[0]['children'][0];

// output json
header('Content-Type: application/json');
echo json_encode($index, JSON_PRETTY_PRINT);

次の json が作成されます (ここでは PHP 5.4s を使用JSON_PRETTY_PRINT):

{
    "id": 5273,
    "parent": 0,
    "name": "John Doe",
    "data": {

    },
    "children": [
        {
            "id": 6032,
            "parent": 5273,
            "name": "Sally Smith",
            "data": {

            },
            "children": [
                {
                    "id": 6034,
                    "parent": 6032,
                    "name": "Mike Jones",
                    "data": {

                    },
                    "children": [
                        {
                            "id": 6035,
                            "parent": 6034,
                            "name": "Jason Williams",
                            "data": {

                            }
                        }
                    ]
                }
            ]
        },
        {
            "id": 6036,
            "parent": 5273,
            "name": "Sara Johnson",
            "data": {

            }
        },
        {
            "id": 6037,
            "parent": 5273,
            "name": "Dave Wilson",
            "data": {

            },
            "children": [
                {
                    "id": 6038,
                    "parent": 6037,
                    "name": "Amy Martin",
                    "data": {

                    }
                }
            ]
        }
    ]
}
于 2012-12-25T19:52:29.213 に答える
2

次のコードは仕事をします..必要に応じて少し調整することができます.

$data = array(
    '5273' => array( 'id' =>5273, 'name'=> 'John Doe', 'parent'=>''),
    '6032' => array( 'id' =>6032, 'name'=> 'Sally Smith', 'parent'=>'5273'),
    '6034' => array( 'id' =>6034, 'name'=> 'Mike Jones ', 'parent'=>'6032'),
    '6035' => array( 'id' =>6035, 'name'=> 'Jason Williams', 'parent'=>'6034')
    );

$fdata = array();


function ConvertToMulti($data) {
    global $fdata;

    foreach($data as $k => $v)
    {
        if(empty($v['parent'])){
            unset($v['parent']);
        $v['data'] = array();
        $v['children'] = array();
            $fdata[] = $v;
        }
        else {
            findParentAndInsert($v, $fdata);
        }

    }
}

function findParentAndInsert($idata, &$ldata) {

    foreach ($ldata as $k=>$v) {

        if($ldata[$k]['id'] == $idata['parent']) {
            unset($idata['parent']);
        $idata['data'] = array();
        $idata['children'] = array();
            $ldata[$k]['children'][] = $idata;
            return;
        }
        else if(!empty($v['children']))
            findParentAndInsert($idata, $ldata[$k]['children']);
    }
}


print_r($data);
ConvertToMulti($data);
echo "AFTER\n";
print_r($fdata);

http://codepad.viper-7.com/Q5Buaz

于 2012-06-28T08:14:03.173 に答える