11

可能重复:
根据父 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);
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 上建立索引。这是第一步。

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

有一个“虚拟”节点,即 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": {

                    }
                }
            ]
        }
    ]
}
于 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 回答