PHP从具有关系数据的数组创建多维数组[重复]

Posted

技术标签:

【中文标题】PHP从具有关系数据的数组创建多维数组[重复]【英文标题】:PHP Create a Multidimensional Array from an array with relational data [duplicate] 【发布时间】:2012-06-29 16:17:13 【问题描述】:

可能重复:Converting an array from one to multi-dimensional based on parent ID values

我正在使用 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);

【问题讨论】:

您发布的初始格式一个多维数组。这不应该在 json 编码中工作吗? Ben Roux,是的,这是一个多维数组,但生成该 JSON 的格式不正确。 你试过什么?发布你的代码你是如何准备数组的。 Sanjay,我在我的问题中添加了一些我的工作。我无法在 cmets 中获得正确的格式。我也尝试过do-while,但也失败了。 Yoshi,我回过头来记下所有以前的答案都是某些解决方案。我希望这有帮助。我以后会更好地跟上这一点。 【参考方案1】:
<?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

【讨论】:

耀西,谢谢。我针对测试运行了您的代码,并且效果很好。但是,当我实施一些现实世界的数据时,可能是 300-400 人。我得到一个 PHP 用尽 128mb 的内存错误。我知道 300-400 条记录比我提供的示例要多,但我认为它不会被视为大型数据集。有任何想法吗?这使用这么多内存有意义吗? @maestrojed 我的第一个版本出现错误(可能是内存泄漏的原因),请查看更新。 这很有效,而且超出了我的预期。谢谢您的帮助。我期待着分析它并学习一些东西! @Yoshi 经过几次检查后,我发现如果您有多个***父母,您应该return $m[$r]。无论如何,感谢您的解决方案。 @Yoshi 明白了,谢谢兄弟,你的意思是这个 (ref - &) 将变量本身放在子部分中,而不是它的值的副本,它在最终输出中获得它的值【参考方案2】:

好的,这就是它的工作原理,实际上您在开始时并没有走得太远,但您实际寻找的是参考资料。这是一个通用程序:

由于父节点和子节点的 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://***.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": 

                    
                
            ]
        
    ]

【讨论】:

你能解释一下 unset($row);正在做 @LovepreetSinghBatth:它是“因为我们使用引用,所以最后一行注意在循环后取消设置存储在 $row 中的引用。”在它所在的示例下方。【参考方案3】:

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

$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

【讨论】:

我会在早上继续尝试这个。在第一次实施时,它似乎有问题。我还不确定是什么,并将尝试详细评论。当我实现它时,我没有收到错误,结构似乎正确,但缺少很多数据。 请注意几件事,首先,用你的填充 $data 数组。它没有您在问题中使用的所有值。其次,您可以将 $fdata 设为 ConvertToMulti 函数的本地变量。使其全局化可能会导致您的实施出现问题。祝您实施顺利

以上是关于PHP从具有关系数据的数组创建多维数组[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何从 PHP 中的多维数组中删除重复值

如何从 PHP 中的多维数组中删除重复值 [重复]

在 PHP 中递归创建多维数组

从字符串创建多维数组[重复]

如何从 mySQL 和 PHP 检索结果为多维数组?

如果两个值匹配,则从 php 中的多维关联数组中删除重复项