PHP 从具有关系数据的数组创建多维数组


PHP Create a Multidimensional Array from an array with relational data

可能的重复项:
根据父 ID 值将数组从一维转换为多维

我在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);
<?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

好的,这就是它的工作原理,你实际上在开始时并没有太远,但你实际寻找的是参考。这是一个常规过程:

由于父节点和子节点在其 ID 上存在关系,因此首先需要根据 ID 为数据编制索引。我在这里用一个数组($rows)来模拟你的数据访问,如果你从数据库中读取,它会是类似的。通过此索引编制,您还可以添加其他属性,例如空数据:

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

因此,现在所有条目都根据其 ID 编制索引。这是第一步。

第二步同样直截了当。因为我们现在可以根据每个节点在$index中的 ID 访问每个节点,我们可以将子节点分配给它们的父节点。

有一个"虚拟"节点,即 ID 为 0 的节点。它不存在于任何行中,但是,如果我们也可以向其添加子项,则可以将此子集合用作所有根节点的存储区,在您的情况下,只有一个根节点。

当然,对于 ID 0 ,我们不应该处理父级 - 因为它不存在。

所以让我们这样做。我们在这里使用引用,因为否则同一个节点不能同时是父节点和子节点:

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

因为我们使用引用,所以最后一行注意在循环后取消设置存储在$row中的引用。

现在所有的孩子都被分配给他们的父母。这可能已经是了,但是不要忘记最后一步,应该访问输出的实际节点。

为简洁起见,只需将根节点分配给$index本身。如果我们记得,我们想要的唯一根节点是 ID 为 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": {
                    }
                }
            ]
        }
    ]
}

以下代码将完成这项工作.. 您可能需要根据需要稍作调整。

$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