将含有父ID的列表转成树

我们知道数据库一般是以一个列表(id,pid)的形式保存树的。如何提取这棵树呢?最简单的方法就是根据pid循环查表。但是毫无疑问,这会产生巨大的数据库查询开销。

那么一般建议的方法是一次性将全部相关数据全查出来,但是这就涉及到一个问题,如何快速的构建一棵树。

我曾经一直以为,这是一个复杂的操作,至少需要一个递归,时间复杂度不会是O(n)。

前段时间,一个工作上的需求,需要解决这个问题。我仔细想了想,发现完全可以通过单层循环解决这个问题,实现如下:

 1 function list2Tree($listItem, $idx = 'id', $pIdx = 'pid', $childKey= 'list'){
 2     $map = array();
 3     $pMap = array();
 4 
 5     foreach($listItem as $item){
 6         $id = $item[$idx];
 7         $pid = $item[$pIdx];
 8         $map[$id] = &$item;
 9         unset($item);
10     }       
11             
12     foreach($map as $id => &$item){
13         $pid = $item[$pIdx];
14         empty($item[$childKey]) && $item[$childKey] = array();
15 
16         if(! isset($map[$pid])){
17             $pMap[$id] = &$item; 
18         }       
19         else{   
20             $pItem= &$map[$pid];
21             $pItem[$childKey][] = &$item;
22         }   
23 
24         unset($item, $pItem);
25     }
26    
27     return array_shift($pMap);
28 }

测试一下:

 1 // 路径方便识别父子关系
 2 $json = <<<JSON
 3 [
 4     {
 5         "id": 2,
 6         "pid": 1,
 7         "path": "/se"
 8     },
 9     {
10         "id": 3,
11         "pid": 2,
12         "path": "/se/4901"
13     },
14     {
15         "id": 4,
16         "pid": 5,
17         "path": "/se/4901/mask/query"
18     },
19         {
20         "id": 5,
21         "pid": 3,
22         "path": "/se/4901/mask"
23     },
24     {
25         "id": 6,
26         "pid": 2,
27         "path": "/se/4902"
28     },
29     {
30         "id": 7,
31         "pid": 6,
32         "path": "/se/4902/mask"
33     }
34 ]
35 JSON;
36 
37 $list = json_decode($json, true);
38 
39 var_dump(list2Tree($list));

结果:

array(4) {
  ["id"]=>
  int(2)
  ["pid"]=>
  int(1)
  ["path"]=>
  string(3) "/se"
  ["list"]=>
  array(2) {
    [0]=>
    array(4) {
      ["id"]=>
      int(3)
      ["pid"]=>
      int(2)
      ["path"]=>
      string(8) "/se/4901"
      ["list"]=>
      array(1) {
        [0]=>
        array(4) {
          ["id"]=>
          int(5)
          ["pid"]=>
          int(3)
          ["path"]=>
          string(13) "/se/4901/mask"
          ["list"]=>
          array(0) {
          }
        }
      }
    }
    [1]=>
    array(4) {
      ["id"]=>
      int(6)
      ["pid"]=>
      int(2)
      ["path"]=>
      string(8) "/se/4902"
      ["list"]=>
      array(1) {
        [0]=>
        array(4) {
          ["id"]=>
          int(7)
          ["pid"]=>
          int(6)
          ["path"]=>
          string(13) "/se/4902/mask"
          ["list"]=>
          array(0) {
          }
        }
      }
    }
  }
}

成功把列表转成了树

posted @ 2016-02-25 17:23  南十字  阅读(975)  评论(0编辑  收藏  举报