分層資料 Hierarchical Data 探索 (1.遞迴) 無限極分類

arunfung發表於2019-05-06

分層資料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;
}

全部更新完成。

  • 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
  • 文章來源https://blog.arunfung.com

相關文章