我们知道数据库一般是以一个列表(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));

结果:

  1. array(4) {
  2. ["id"]=>
  3. int(2)
  4. ["pid"]=>
  5. int(1)
  6. ["path"]=>
  7. string(3) "/se"
  8. ["list"]=>
  9. array(2) {
  10. [0]=>
  11. array(4) {
  12. ["id"]=>
  13. int(3)
  14. ["pid"]=>
  15. int(2)
  16. ["path"]=>
  17. string(8) "/se/4901"
  18. ["list"]=>
  19. array(1) {
  20. [0]=>
  21. array(4) {
  22. ["id"]=>
  23. int(5)
  24. ["pid"]=>
  25. int(3)
  26. ["path"]=>
  27. string(13) "/se/4901/mask"
  28. ["list"]=>
  29. array(0) {
  30. }
  31. }
  32. }
  33. }
  34. [1]=>
  35. array(4) {
  36. ["id"]=>
  37. int(6)
  38. ["pid"]=>
  39. int(2)
  40. ["path"]=>
  41. string(8) "/se/4902"
  42. ["list"]=>
  43. array(1) {
  44. [0]=>
  45. array(4) {
  46. ["id"]=>
  47. int(7)
  48. ["pid"]=>
  49. int(6)
  50. ["path"]=>
  51. string(13) "/se/4902/mask"
  52. ["list"]=>
  53. array(0) {
  54. }
  55. }
  56. }
  57. }
  58. }
  59. }

成功把列表转成了树

将含有父ID的列表转成树的更多相关文章

  1. 传递一个父id返回所有子id的用法,可用于删除父级以下的所有子级

    先在common文件夹建立一个function.php文件,然后写一个递归函数,传递一个父id返回所有子id,如下: function getChildrenId($node,$pid){ $arr= ...

  2. vue通过id从列表页跳转到对应的详情页

    1. 列表页:列表页带id跳转到详情页 详情页:把id传回到后台就可以获取到数据了 2.列表页跳转到详情页并更改详情页的标题 列表页:带id和页面标题的typeid跳转到详情页 详情页:在html绑定 ...

  3. VUE通过id从列表页跳转到相对的详情页

    新闻列表页面: 在这里我用a标签进行跳转,在vue里面可以这样写<router-link></router-link> 1 <router-link :to=" ...

  4. 无限极分类,传递一个父ID,返回所有子集

    方法: static public function getChildren($data,$pid){ $arr=array(); foreach ($data as $v) { if ($v['pi ...

  5. Oracle由ID生成父ID的函数

    /*表结构*/ CREATE TABLE ly_md ( bh BYTE), mc BYTE), pym BYTE), f_bh BYTE), ch NUMBER, ID NUMBER ); INSE ...

  6. MySQL中进行树状所有子节点的查询 . mysql根据父id 查询所有的子id

    在Oracle 中我们知道有一个 Hierarchical Queries 通过CONNECT BY 我们可以方便的查了所有当前节点下的所有子节点.但很遗憾,在MySQL的目前版本中还没有对应的功能. ...

  7. 递归根据父ID 找所有子类ID

    function getinfo($pid){ $str = ''; $row = M('user')->where(array('pid'=>$pid))->select(); i ...

  8. ajax通过新闻id获取列表

    <div class="index_main">        <div class="page_l">           <i ...

  9. SQL在一张表中根据父ID获取所有的子ID

    with a as ( select id,name,parentid from categories where id=53 union all select x.id,x.name,x.paren ...

随机推荐

  1. SwitchySharp怎样设置 ( proxy switch!的设置与使用方法)

    规则列表URL  https://autoproxy-G{过}F{滤}Wlist.googlecode.com/svn/trunk/G{过}F{滤}Wlist.txt 注:不同的代{过}{滤}理  相 ...

  2. 理解ATL中的一些汇编代码(通过Thunk技术来调用类成员函数)

    我们知道ATL(活动模板库)是一套很小巧高效的COM开发库,它本身的核心文件其实没几个,COM相关的(主要是atlbase.h, atlcom.h),另外还有一个窗口相关的(atlwin.h), 所以 ...

  3. android中对线程池的理解与使用

    前段时间有幸接到腾讯上海分公司的 Android开发面试,虽然最后一轮被毙了.但还是得总结一下自己在android开发中的一些盲点,最让我尴尬的是面试官问我几个android中线程池的使用与理解..哎 ...

  4. MPlayer播放器安装

    http://www.mplayerhq.hu/MPlayer/releases/MPlayer-1.1.1.tar.xz [tim@L MPlayer-1.1.1]$ mplayer         ...

  5. HDU_1239——再次调用外星智慧

    Problem Description A message from humans to extraterrestrial intelligence was sent through the Arec ...

  6. linux下的java远程调试jpda+tomcat

    项目放到linux服务器了,服务器的环境或者数据可能和我们本地不一样,这个时候我们可能需要远程的断点进行调试,来查看请求过程中的各个变量的值.这里我们的应用服务器用的tomcat5.5.17 这个时候 ...

  7. git命令使用方法

    git安装包 http://c35.yunpan.360.cn/my/?sid=#%2F%E5%AE%89%E8%A3%85%E5%8C%85%2FGit%E5%AE%89%E8%A3%85%2F g ...

  8. checkbox 与JS的应用

    JS是一种基于(面向)对象的语言.所有的东西都基本上是对象. 基于对象和面向对象概念上基本上没有什么区别. js没有类,它把类功能称为原型对象.是同一个概念.主要是因为js没有class关键字.类== ...

  9. android启动优化

    ############################################## # power on till android lock screen comes up # # get ...

  10. C编程风格.

    C语言编程风格. 关于编程风格,不同书上有不同规范,不同公司都有自己的一套定义.根据自己的编程习惯做个简要说明. 1.变量定义 在定义变量时,前缀使用变量的类型,之后使用表现变量用途的英文单词或单词缩 ...