47

分层数据Hierarchical Data探索(1.递归)

 5 years ago
source link: https://www.tuicool.com/articles/euymEbI
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

分层数据Hierarchical Data探索(例如:无限级分类、多级菜单、省份城市)

引言

什么是分层数据?

类似于树形结构,除了根节点和叶子节点外,所有节点都有一个父节点和一个或多个子节点。

大多数同学都曾在数据库中处理过分层数据(hierarchical data),分层数据存在于许多基于数据库的应用程序中,包括论坛和邮件列表中的分类、商业组织图表、内容管理系统的分类、产品分类、无限级分类、多级菜单、省份城市等等。但是因为关系数据库中的表没有层次关系,只是简单的平面化的列表;而分层数据具有父-子关系,显然关系数据库中的表不能自然地表现出其分层的特性。

接下来我会先通过一般方法和递归( recursion )方法来实现无限极分类,然后再通过 两种数据模型 来谈一谈分层数据的处理。

三种方式的变量传递

  • & 引用赋值
function doloop1(&$i = 1)
{
    print_r($i);
    $i++;
    if ($i <= 10) {
        doloop1($i);
    }
}
doloop1();
  • static 静态变量
function doloop2()
{
    static $i = 1;
    print_r($i);
    $i++;
    if ($i <= 10) {
        doloop2();
    }
}

doloop2();
  • global 全局变量
$i = 1;
function doloop3()
{
    global $i;
    echo $i;
    $i++;
    if ($i <= 10) {
        doloop3();
    }
}
doloop3();

构建模拟数据

# 模拟数据
       $data = [
            ['id' => 1, 'title' => 'Electronics', 'parent_id' => 0],
            ['id' => 2, 'title' => 'Laptops & PC', 'parent_id' => 1],
            ['id' => 3, 'title' => 'Laptops', 'parent_id' => 2],
            ['id' => 4, 'title' => 'PC', 'parent_id' => 2],
            ['id' => 5, 'title' => 'Cameras & photo', 'parent_id' => 1],
            ['id' => 6, 'title' => 'Camera', 'parent_id' => 5],
            ['id' => 7, 'title' => 'Phones & Accessories', 'parent_id' => 1],
            ['id' => 8, 'title' => 'Smartphones', 'parent_id' => 7],
            ['id' => 9, 'title' => 'Android', 'parent_id' => 8],
            ['id' => 10, 'title' => 'iOS', 'parent_id' => 8],
            ['id' => 11, 'title' => 'Other Smartphones', 'parent_id' => 8],
            ['id' => 12, 'title' => 'Batteries', 'parent_id' => 7],
            ['id' => 13, 'title' => 'Headsets', 'parent_id' => 7],
            ['id' => 14, 'title' => 'Screen Protectors', 'parent_id' => 7],
        ];

获取无限极分类

/**
 * 值引用获取无限极分类树
 * 
 * @param array $data
 * @return array
 */
function make_tree($data)
{  
    $refer = array();  
    $tree = array();  
    foreach($data as $k => $v){  
        $refer[$v['id']] = & $data[$k];  //创建主键的数组引用  
    }  

    foreach($data as $k => $v){  
        $parent_id = $v['parent_id'];   //获取当前分类的父级id  
        if($parent_id == 0){  
            $tree[] = & $data[$k];   //顶级栏目
        }else{  
            if(isset($refer[$parent_id])){  
                $refer[$parent_id]['children'][] = & $data[$k];  //如果存在父级栏目,则添加进父级栏目的子栏目数组中  
            }  
        }  
    }  

    return $tree;  
}

/**
 * 递归获取无限极分类树
 * 
 * @param array $data
 * @param int $parent_id
 * @param int $level
 * @return array
 */
function make_tree2($data = [], $parent_id = 0, $level = 0)
{
    $tree = [];
    if ($data && is_array($data)) {
        foreach ($data as $v) {
            if ($v['parent_id'] == $parent_id) {
                $tree[] = [
                    'id' => $v['id'],
                    'level' => $level,
                    'title' => $v['title'],
                    'parent_id' => $v['parent_id'],
                    'children' => make_tree2($data, $v['id'], $level + 1),
                ];
            }
        }
    }
    return $tree;
}

获取子节点以及节点的层级

/**
 * 引用赋值方式
 * @param array $data
 * @param int $id
 * @param int $level
 * @return array
 */
function getSubTree($data = [], $id = 0, $level = 0)
{
    static $tree = [];

    foreach ($data as $key => $value) {
        if ($value['parent_id'] == $id) {
            $value['laravel'] = $level;
            $tree[] = $value;
            getSubTree($data, $value['id'], $level + 1);
        }
    }
    return $tree;
}

/**
 * 静态变量方式
 * @param array $data
 * @param int $id
 * @param int $level
 * @return array
 */
function getSubTree($data = [], $id = 0, $level = 0)
{
    static $tree = [];

    foreach ($data as $key => $value) {
        if ($value['parent_id'] == $id) {
            $value['laravel'] = $level;
            $tree[] = $value;
            getSubTree($data, $value['id'], $level + 1);
        }
    }
    return $tree;
}


/**
 * 全局变量方式
 * @param array $data
 * @param int $id
 * @param int $level
 * @return array
 */

$tree = [];  //先申明变量
function getSubTree($data = [], $id = 0, $level = 0)
{
    global $tree;

    foreach ($data as $key => $value) {
        if ($value['parent_id'] == $id) {
            $value['laravel'] = $level;
            $tree[] = $value;
            getSubTree($data, $value['id'], $level + 1);
        }
    }
    return $tree;
}

通过pid获取所有上级分类 常用于面包屑导航

/**
 * getParentsByParentId2($categories, 9)
 *
 * @param array $data
 * @param $parent_id
 * @return array
 */
function getParentsByParentId($data = [], $parent_id)
{
    static $categories = [];

    if ($data && is_array($data)) {
        foreach ($data as $item) {
            if ($item['id'] == $parent_id) {
                $categories[] = $item;
                getParentsByParentId($data, $item['parent_id']);
            }
        }
    }
    return $categories;
}

function getParentsByParentId2($data = [], $parent_id)
{
    $categories = [];

    if ($data && is_array($data)) {
        foreach ($data as $item) {
            if ($item['id'] == $parent_id) {
                $categories[] = $item;
                $categories = array_merge($categories, getParentsByParentId2($data, $item['parent_id']));
            }
        }
    }
    return $categories;
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK